From 3f4222e5e42abf20d58844d4f089cb13846d8c56 Mon Sep 17 00:00:00 2001 From: Conor Wright Date: Wed, 7 Mar 2018 17:17:05 -0500 Subject: [PATCH 01/46] Resolving Card action bar still visable after hiding with *ngIf #1421 --- src/modules/card/card-actions.component.scss | 7 +++++++ src/modules/card/card-actions.component.ts | 1 + src/modules/card/card.component.scss | 2 -- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 src/modules/card/card-actions.component.scss diff --git a/src/modules/card/card-actions.component.scss b/src/modules/card/card-actions.component.scss new file mode 100644 index 000000000..3027c1729 --- /dev/null +++ b/src/modules/card/card-actions.component.scss @@ -0,0 +1,7 @@ +@import "../../scss/mixins"; + +:host { + display: block; + @include sky-border(light, top); + padding: $sky-padding-3_4 0; +} \ No newline at end of file diff --git a/src/modules/card/card-actions.component.ts b/src/modules/card/card-actions.component.ts index aa955f173..7b6db7f03 100644 --- a/src/modules/card/card-actions.component.ts +++ b/src/modules/card/card-actions.component.ts @@ -2,6 +2,7 @@ import { Component } from '@angular/core'; @Component({ selector: 'sky-card-actions', + styleUrls: ['./card-actions.component.scss'], templateUrl: '../shared/simple-content.html' }) export class SkyCardActionsComponent { } diff --git a/src/modules/card/card.component.scss b/src/modules/card/card.component.scss index 21a48c63e..5d6759ed6 100644 --- a/src/modules/card/card.component.scss +++ b/src/modules/card/card.component.scss @@ -88,10 +88,8 @@ } .sky-card-actions { - @include sky-border(light, top); bottom: 0; flex-shrink: 0; - padding: $sky-padding-3_4 0; text-align: center; .sky-context-menu-btn { From a450054956bfa0efa21c71481ea49e9f82c22f08 Mon Sep 17 00:00:00 2001 From: Conor Wright Date: Thu, 8 Mar 2018 10:46:26 -0500 Subject: [PATCH 02/46] Addressed PR style comments --- src/modules/card/card-actions.component.scss | 8 ++++---- src/modules/card/card-actions.component.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/card/card-actions.component.scss b/src/modules/card/card-actions.component.scss index 3027c1729..402369a03 100644 --- a/src/modules/card/card-actions.component.scss +++ b/src/modules/card/card-actions.component.scss @@ -1,7 +1,7 @@ @import "../../scss/mixins"; :host { - display: block; - @include sky-border(light, top); - padding: $sky-padding-3_4 0; -} \ No newline at end of file + display: block; + @include sky-border(light, top); + padding: $sky-padding-3_4 0; +} diff --git a/src/modules/card/card-actions.component.ts b/src/modules/card/card-actions.component.ts index 7b6db7f03..e23730367 100644 --- a/src/modules/card/card-actions.component.ts +++ b/src/modules/card/card-actions.component.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; @Component({ selector: 'sky-card-actions', - styleUrls: ['./card-actions.component.scss'], - templateUrl: '../shared/simple-content.html' + templateUrl: '../shared/simple-content.html', + styleUrls: ['./card-actions.component.scss'] }) export class SkyCardActionsComponent { } From 995f02414453cdf02c207999501630ec4b12b558 Mon Sep 17 00:00:00 2001 From: Conor Wright Date: Tue, 3 Apr 2018 15:35:08 -0400 Subject: [PATCH 03/46] started porting over alert design to toast --- src/modules/toast/toast.component.html | 23 +++++ src/modules/toast/toast.component.scss | 110 ++++++++++++++++++++++++ src/modules/toast/toast.component.ts | 0 src/modules/toast/toast.service.spec.ts | 25 ++++++ src/modules/toast/toast.service.ts | 15 ++++ 5 files changed, 173 insertions(+) create mode 100644 src/modules/toast/toast.component.html create mode 100644 src/modules/toast/toast.component.scss create mode 100644 src/modules/toast/toast.component.ts create mode 100644 src/modules/toast/toast.service.spec.ts create mode 100644 src/modules/toast/toast.service.ts diff --git a/src/modules/toast/toast.component.html b/src/modules/toast/toast.component.html new file mode 100644 index 000000000..3c0070da1 --- /dev/null +++ b/src/modules/toast/toast.component.html @@ -0,0 +1,23 @@ +
+
+ +
diff --git a/src/modules/toast/toast.component.scss b/src/modules/toast/toast.component.scss new file mode 100644 index 000000000..685e74fb4 --- /dev/null +++ b/src/modules/toast/toast.component.scss @@ -0,0 +1,110 @@ +@import "../../scss/variables"; + +.sky-toast { + padding: 0 $sky-padding; + margin-bottom: $sky-margin-double; + border-left: solid 30px; + border-radius: $sky-border-radius; + color: $sky-text-color-default; + display: flex; + flex-direction: row; + align-items: center; + + .sky-toast-content { + padding-top: $sky-padding; + padding-bottom: $sky-padding; + width: 100%; + + ::ng-deep a { + color: change-color($sky-text-color-default, $alpha: 0.8); + text-decoration: underline; + + &:hover { + color: $sky-text-color-default; + } + } + } + + + + button { + margin-left: auto; + width: 32px; + height: 32px; + } +} + +.sky-toast-info { + background-color: $sky-background-color-info; + border-color: $sky-highlight-color-info; + + &:before { + content: "\f06a"; + font-family: FontAwesome; + margin-left: -31px; + margin-right: 20px; + color: $sky-color-white; + } +} + +.sky-toast-success { + background-color: $sky-background-color-success; + border-color: $sky-highlight-color-success; + + &:before { + content: "\f00c"; + font-family: FontAwesome; + margin-left: -32px; + margin-right: 19px; + color: $sky-color-white; + } +} + +.sky-toast-warning { + background-color: $sky-background-color-warning; + border-color: $sky-highlight-color-warning; + + &:before { + content: "\f071"; + font-family: FontAwesome; + margin-left: -32px; + margin-right: 19px; + color: $sky-color-white; + } +} + +.sky-toast-danger { + background-color: $sky-background-color-danger; + border-color: $sky-highlight-color-danger; + + &:before { + content: "\f071"; + font-family: FontAwesome; + margin-left: -32px; + margin-right: 19px; + color: $sky-color-white; + } +} + +.sky-toast-close { + cursor: pointer; + font-weight: bold; + line-height: 1; + margin: 0; + padding: 0; + color: $sky-text-color-default; + opacity: 0.8; + border: none; + background-color: transparent; + display: none; + + &:hover { + opacity: 1.0; + } +} + +.sky-toast-closeable { + .sky-toast-close { + display: block; + } +} diff --git a/src/modules/toast/toast.component.ts b/src/modules/toast/toast.component.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/modules/toast/toast.service.spec.ts b/src/modules/toast/toast.service.spec.ts new file mode 100644 index 000000000..975d776d7 --- /dev/null +++ b/src/modules/toast/toast.service.spec.ts @@ -0,0 +1,25 @@ +import { SkyErrorModalService } from './error-modal.service'; +import { MockModalService } from './fixtures/mocks'; +import { ErrorModalConfig } from './error-modal-config'; +import { SkyErrorModalFormComponent } from './error-modal-form.component'; + +describe('Error modal service', () => { + it('Test open is called with correct parameters', () => { + let modalService = new MockModalService(undefined, undefined, undefined); + + const config: ErrorModalConfig = { + errorTitle: 'Error title', + errorDescription: 'Description of error', + errorCloseText: 'Close button text' + }; + + const expectedProvider = { provide: ErrorModalConfig, useValue: config }; + + let service = new SkyErrorModalService(modalService); + service.open(config); + + expect(modalService.openCalls.length).toBe(1); + expect(modalService.openCalls[0].component).toBe(SkyErrorModalFormComponent); + expect(modalService.openCalls[0].providers).toEqual([expectedProvider]); + }); +}); diff --git a/src/modules/toast/toast.service.ts b/src/modules/toast/toast.service.ts new file mode 100644 index 000000000..f16bd5a3d --- /dev/null +++ b/src/modules/toast/toast.service.ts @@ -0,0 +1,15 @@ +import { Injectable } from '@angular/core'; +import { ErrorModalConfig } from './error-modal-config'; +import { SkyErrorModalFormComponent } from './error-modal-form.component'; +import { SkyModalService } from '../modal/modal.service'; + +@Injectable() +export class SkyErrorModalService { + constructor(private modal: SkyModalService) {} + + public open(config: ErrorModalConfig) { + const providers = [{ provide: ErrorModalConfig, useValue: config }]; + + this.modal.open(SkyErrorModalFormComponent, providers); + } +} From f4c10f0097e019c791203ac8c7c9d6024cedf10b Mon Sep 17 00:00:00 2001 From: Conor Wright Date: Wed, 4 Apr 2018 11:21:43 -0400 Subject: [PATCH 04/46] began working on toast component from scratch --- src/modules/toast/toast.component.html | 42 ++++++------ src/modules/toast/toast.service.ts | 90 +++++++++++++++++++++++--- 2 files changed, 101 insertions(+), 31 deletions(-) diff --git a/src/modules/toast/toast.component.html b/src/modules/toast/toast.component.html index 3c0070da1..c4172847f 100644 --- a/src/modules/toast/toast.component.html +++ b/src/modules/toast/toast.component.html @@ -1,23 +1,19 @@ -
-
- -
+
+ +
\ No newline at end of file diff --git a/src/modules/toast/toast.service.ts b/src/modules/toast/toast.service.ts index f16bd5a3d..c69a8c399 100644 --- a/src/modules/toast/toast.service.ts +++ b/src/modules/toast/toast.service.ts @@ -1,15 +1,89 @@ import { Injectable } from '@angular/core'; -import { ErrorModalConfig } from './error-modal-config'; -import { SkyErrorModalFormComponent } from './error-modal-form.component'; -import { SkyModalService } from '../modal/modal.service'; +import { BehaviorSubject } from 'rxjs/BehaviorSubject'; +import { Observable } from 'rxjs/Observable'; + +export enum ToastType { + Info, + Success, + Warning, + Danger +} + +export interface Message { + id: string, + message: string, + toastType: string, + timeout?: NodeJS.Timer +} +export interface ToastConfig { + message?: string, + disableTimeout?: boolean, + timeout?: number, + toastType?: ToastType +} @Injectable() -export class SkyErrorModalService { - constructor(private modal: SkyModalService) {} +export class SkyToastService { + + private _messages: Message[] = []; + private _messageList: BehaviorSubject = new BehaviorSubject([]); + public get messageList(): Observable { return this._messageList.asObservable() } + + constructor() {} + + public openMessage(message: string, config?: ToastConfig) { + config.message = message; + return this.open(config); + } + + public open(config: ToastConfig) { + let message: Message = this.createMessage(config); + + this._messages.push(message); + this._messageList.next(this._messages); + } + + public close(messageId: string) { + let message: Message = this._messages.reduce((prev, cur) => prev.id === messageId ? prev : cur); + if (!message) { + throw 'SkyToast message not found.'; + } + + if (message.timeout) { + clearTimeout(message.timeout); + } + this._messages.map(message => message.id !== messageId); + this._messageList.next(this._messages); + } + + private createMessage(config: ToastConfig): Message { + if (!config.message) { + throw 'A message must be provided.'; + } + let message: Message = { + message: config.message, + toastType: 'info', + id: '_' + Math.random().toString(36).substr(2, 9) + }; + + if (!config.disableTimeout) { + message.timeout = setTimeout(() => { + this.close(message.id); + }, config.timeout || 10000); + } - public open(config: ErrorModalConfig) { - const providers = [{ provide: ErrorModalConfig, useValue: config }]; + switch(config.toastType) { + case ToastType.Success: + message.toastType = 'success'; + break; + case ToastType.Warning: + message.toastType = 'warning'; + break; + case ToastType.Danger: + message.toastType = 'danger'; + break; + } - this.modal.open(SkyErrorModalFormComponent, providers); + return message; } } From c8994aed0f80519de848e0904729320a339ae2f0 Mon Sep 17 00:00:00 2001 From: Conor Wright Date: Wed, 4 Apr 2018 16:29:33 -0400 Subject: [PATCH 05/46] got a base demo and toast service running --- src/core.ts | 3 ++ src/demo.ts | 2 + src/demos/demo.service.ts | 17 ++++++ src/demos/index.ts | 1 + src/demos/toast/index.ts | 1 + src/demos/toast/toast-demo.component.html | 4 ++ src/demos/toast/toast-demo.component.ts | 17 ++++++ src/locales/resources_en_US.json | 4 ++ src/modules/toast/index.ts | 3 ++ src/modules/toast/toast.component.html | 12 ++--- src/modules/toast/toast.component.scss | 8 +-- src/modules/toast/toast.component.ts | 19 +++++++ src/modules/toast/toast.module.ts | 26 +++++++++ src/modules/toast/toast.service.ts | 64 +++++++++++++---------- 14 files changed, 140 insertions(+), 41 deletions(-) create mode 100644 src/demos/toast/index.ts create mode 100644 src/demos/toast/toast-demo.component.html create mode 100644 src/demos/toast/toast-demo.component.ts create mode 100644 src/modules/toast/index.ts create mode 100644 src/modules/toast/toast.module.ts diff --git a/src/core.ts b/src/core.ts index c4996b857..cd0476c16 100644 --- a/src/core.ts +++ b/src/core.ts @@ -62,6 +62,7 @@ import { SkyTabsModule } from './modules/tabs'; import { SkyTextExpandModule } from './modules/text-expand'; import { SkyTextExpandRepeaterModule } from './modules/text-expand-repeater'; import { SkyTextHighlightModule } from './modules/text-highlight'; +import { SkyToastModule } from './modules/toast'; import { SkyTokensModule } from './modules/tokens'; import { SkyToolbarModule } from './modules/toolbar'; import { SkyTilesModule } from './modules/tiles'; @@ -123,6 +124,7 @@ import { SkyWaitModule } from './modules/wait'; SkyTextHighlightModule, SkyTilesModule, SkyTimepickerModule, + SkyToastModule, SkyTokensModule, SkyToolbarModule, SkyUrlValidationModule, @@ -186,6 +188,7 @@ export * from './modules/text-expand-repeater'; export * from './modules/text-highlight'; export * from './modules/tiles'; export * from './modules/timepicker'; +export * from './modules/toast'; export * from './modules/tokens'; export * from './modules/toolbar'; export * from './modules/url-validation'; diff --git a/src/demo.ts b/src/demo.ts index dda652210..2685f5ce3 100644 --- a/src/demo.ts +++ b/src/demo.ts @@ -69,6 +69,7 @@ import { SkyTextHighlightDemoComponent, SkyTileDemoComponent, SkyTimepickerDemoComponent, + SkyToastDemoComponent, SkyTokensDemoComponent, SkyToolbarDemoComponent, SkyUrlValidationDemoComponent, @@ -147,6 +148,7 @@ const components = [ SkyTextHighlightDemoComponent, SkyTileDemoComponent, SkyTimepickerDemoComponent, + SkyToastDemoComponent, SkyTokensDemoComponent, SkyToolbarDemoComponent, SkyUrlValidationDemoComponent, diff --git a/src/demos/demo.service.ts b/src/demos/demo.service.ts index 5d2829c3e..347a7bfdb 100644 --- a/src/demos/demo.service.ts +++ b/src/demos/demo.service.ts @@ -51,6 +51,7 @@ import { SkyTextHighlightDemoComponent, SkyTileDemoComponent, SkyTimepickerDemoComponent, + SkyToastDemoComponent, SkyTokensDemoComponent, SkyToolbarDemoComponent, SkyUrlValidationDemoComponent, @@ -996,6 +997,22 @@ export class SkyDemoService { } ] }, + { + name: 'Toast', + component: SkyToastDemoComponent, + files: [ + { + name: 'toast-demo.component.html', + fileContents: require('!!raw-loader!./toast/toast-demo.component.html') + }, + { + name: 'toast-demo.component.ts', + fileContents: require('!!raw-loader!./toast/toast-demo.component.ts'), + componentName: 'SkyToastDemoComponent', + bootstrapSelector: 'sky-toast-demo' + } + ] + }, { name: 'Tokens', component: SkyTokensDemoComponent, diff --git a/src/demos/index.ts b/src/demos/index.ts index fb442aa95..44523d115 100644 --- a/src/demos/index.ts +++ b/src/demos/index.ts @@ -44,6 +44,7 @@ export * from './text-expand'; export * from './text-highlight'; export * from './tile'; export * from './timepicker'; +export * from './toast'; export * from './tokens'; export * from './toolbar'; export * from './url-validation'; diff --git a/src/demos/toast/index.ts b/src/demos/toast/index.ts new file mode 100644 index 000000000..451957a7a --- /dev/null +++ b/src/demos/toast/index.ts @@ -0,0 +1 @@ +export * from './toast-demo.component'; diff --git a/src/demos/toast/toast-demo.component.html b/src/demos/toast/toast-demo.component.html new file mode 100644 index 000000000..79391e907 --- /dev/null +++ b/src/demos/toast/toast-demo.component.html @@ -0,0 +1,4 @@ +
+ + +
\ No newline at end of file diff --git a/src/demos/toast/toast-demo.component.ts b/src/demos/toast/toast-demo.component.ts new file mode 100644 index 000000000..00a0b75b4 --- /dev/null +++ b/src/demos/toast/toast-demo.component.ts @@ -0,0 +1,17 @@ +import { Component } from '@angular/core'; + +import { + SkyToastService +} from '../../core'; + +@Component({ + selector: 'sky-toast-demo', + templateUrl: './toast-demo.component.html' +}) +export class SkyToastDemoComponent { + constructor(private toastSvc: SkyToastService) { } + + public openMessage() { + this.toastSvc.openMessage("Bananas aren't shoes"); + } +} diff --git a/src/locales/resources_en_US.json b/src/locales/resources_en_US.json index 92c0f6a49..f85dc526c 100644 --- a/src/locales/resources_en_US.json +++ b/src/locales/resources_en_US.json @@ -819,6 +819,10 @@ "_description": "The close button for the timepicker modal", "message": "Done" }, + "toast_close": { + "_description": "Screen reader text for the close button on toasts", + "message": "Close the toast" + }, "token_dismiss_button_title": { "_description": "The default text for the token dismiss button title.", "message": "Remove item" diff --git a/src/modules/toast/index.ts b/src/modules/toast/index.ts new file mode 100644 index 000000000..cde4e0f1d --- /dev/null +++ b/src/modules/toast/index.ts @@ -0,0 +1,3 @@ +export { SkyToastComponent } from './toast.component'; +export { SkyToastService } from './toast.service'; +export { SkyToastModule } from './toast.module'; diff --git a/src/modules/toast/toast.component.html b/src/modules/toast/toast.component.html index c4172847f..e1a317b01 100644 --- a/src/modules/toast/toast.component.html +++ b/src/modules/toast/toast.component.html @@ -1,19 +1,19 @@
-
\ No newline at end of file diff --git a/src/modules/toast/toast.component.scss b/src/modules/toast/toast.component.scss index 685e74fb4..fc1a6e03b 100644 --- a/src/modules/toast/toast.component.scss +++ b/src/modules/toast/toast.component.scss @@ -96,15 +96,9 @@ opacity: 0.8; border: none; background-color: transparent; - display: none; + display: block; &:hover { opacity: 1.0; } } - -.sky-toast-closeable { - .sky-toast-close { - display: block; - } -} diff --git a/src/modules/toast/toast.component.ts b/src/modules/toast/toast.component.ts index e69de29bb..eba9c4676 100644 --- a/src/modules/toast/toast.component.ts +++ b/src/modules/toast/toast.component.ts @@ -0,0 +1,19 @@ +import { Component, OnInit } from '@angular/core'; +import { SkyToastService } from './toast.service'; +import { Observable } from 'rxjs/Observable'; + +@Component({ + selector: 'sky-toast', + templateUrl: './toast.component.html', + styleUrls: ['./toast.component.scss'], +}) +export class SkyToastComponent implements OnInit { + + messages: Observable; + + constructor(private toast: SkyToastService) { } + + ngOnInit() { + this.messages = this.toast.getMessages + } +} \ No newline at end of file diff --git a/src/modules/toast/toast.module.ts b/src/modules/toast/toast.module.ts new file mode 100644 index 000000000..80edcc94a --- /dev/null +++ b/src/modules/toast/toast.module.ts @@ -0,0 +1,26 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SkyToastService } from './toast.service'; +import { SkyToastComponent } from './toast.component'; +import { SkyResourcesModule } from '../resources'; + +export { SkyToastService } + +@NgModule({ + declarations: [ + SkyToastComponent + ], + imports: [ + CommonModule, SkyResourcesModule + ], + exports: [ + SkyToastComponent + ], + providers: [ + SkyToastService + ], + entryComponents: [ + ] +}) +export class SkyToastModule { +} diff --git a/src/modules/toast/toast.service.ts b/src/modules/toast/toast.service.ts index c69a8c399..36205dfc5 100644 --- a/src/modules/toast/toast.service.ts +++ b/src/modules/toast/toast.service.ts @@ -9,11 +9,24 @@ export enum ToastType { Danger } -export interface Message { - id: string, - message: string, - toastType: string, - timeout?: NodeJS.Timer +export class Message { + public timeout?: NodeJS.Timer; + private _isClosed: BehaviorSubject = new BehaviorSubject(false); + public get isClosed(): Observable { return this._isClosed.asObservable() } + + constructor(public message: string, public toastType: string, private removeFromQueue: Function, timeout?: number) { + if (timeout) { + this.timeout = setTimeout(this.close, timeout); + } + } + + public close = () => { + if (this.timeout) { + clearTimeout(this.timeout); + } + this.removeFromQueue(this); + this._isClosed.next(true); + } } export interface ToastConfig { message?: string, @@ -27,11 +40,11 @@ export class SkyToastService { private _messages: Message[] = []; private _messageList: BehaviorSubject = new BehaviorSubject([]); - public get messageList(): Observable { return this._messageList.asObservable() } + public get getMessages(): Observable { return this._messageList.asObservable() } constructor() {} - public openMessage(message: string, config?: ToastConfig) { + public openMessage(message: string, config: ToastConfig = {}) { config.message = message; return this.open(config); } @@ -43,47 +56,42 @@ export class SkyToastService { this._messageList.next(this._messages); } - public close(messageId: string) { - let message: Message = this._messages.reduce((prev, cur) => prev.id === messageId ? prev : cur); - if (!message) { - throw 'SkyToast message not found.'; + private removeFromQueue: Function = (message: Message) => { + if (this._messages.length == 0) { + throw 'The supplied message is not active.'; } - - if (message.timeout) { - clearTimeout(message.timeout); + let foundMessage: Message = this._messages.reduce((prev, cur) => prev === message ? prev : cur); + if (!foundMessage) { + throw 'The supplied message is not active.'; } - this._messages.map(message => message.id !== messageId); + + this._messages = this._messages.filter(message => message !== message); this._messageList.next(this._messages); - } + }; private createMessage(config: ToastConfig): Message { if (!config.message) { throw 'A message must be provided.'; } - let message: Message = { - message: config.message, - toastType: 'info', - id: '_' + Math.random().toString(36).substr(2, 9) - }; + let timeout: number; if (!config.disableTimeout) { - message.timeout = setTimeout(() => { - this.close(message.id); - }, config.timeout || 10000); + timeout = config.timeout || 10000; } + let toastType: string = 'info'; switch(config.toastType) { case ToastType.Success: - message.toastType = 'success'; + toastType = 'success'; break; case ToastType.Warning: - message.toastType = 'warning'; + toastType = 'warning'; break; case ToastType.Danger: - message.toastType = 'danger'; + toastType = 'danger'; break; } - return message; + return new Message(config.message, toastType, this.removeFromQueue, timeout); } } From a49ebf3bd90d960bb1ddaec8fb61c272e45daa20 Mon Sep 17 00:00:00 2001 From: Conor Wright Date: Tue, 10 Apr 2018 12:00:33 -0400 Subject: [PATCH 06/46] Got the base toast service functional --- src/modules/toast/toast.service.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/toast/toast.service.ts b/src/modules/toast/toast.service.ts index 36205dfc5..439058b3c 100644 --- a/src/modules/toast/toast.service.ts +++ b/src/modules/toast/toast.service.ts @@ -54,6 +54,8 @@ export class SkyToastService { this._messages.push(message); this._messageList.next(this._messages); + + return message; } private removeFromQueue: Function = (message: Message) => { @@ -65,7 +67,7 @@ export class SkyToastService { throw 'The supplied message is not active.'; } - this._messages = this._messages.filter(message => message !== message); + this._messages = this._messages.filter(msg => msg !== message); this._messageList.next(this._messages); }; From 28c09b6d812905da033dddb1509d8834c61ba8cb Mon Sep 17 00:00:00 2001 From: Conor Wright Date: Tue, 10 Apr 2018 13:01:32 -0400 Subject: [PATCH 07/46] moved the toaster to the bottom right --- src/modules/toast/toast.component.scss | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/modules/toast/toast.component.scss b/src/modules/toast/toast.component.scss index fc1a6e03b..bef7977b8 100644 --- a/src/modules/toast/toast.component.scss +++ b/src/modules/toast/toast.component.scss @@ -1,5 +1,14 @@ @import "../../scss/variables"; +.sky-toaster { + bottom: 0; + right: 0; + display: block; + position: fixed; + padding-bottom: $sky-margin-double; + padding-right: $sky-margin-double; +} + .sky-toast { padding: 0 $sky-padding; margin-bottom: $sky-margin-double; From 3b5d5cb48295b1c6100f480bd05e170e8ccaaaf5 Mon Sep 17 00:00:00 2001 From: Conor Wright Date: Tue, 10 Apr 2018 15:39:08 -0400 Subject: [PATCH 08/46] Steve's comments. Added fading close to toasts --- src/demos/toast/toast-demo.component.html | 1 - src/modules/toast/toast-adapter.service.ts | 30 +++++++ src/modules/toast/toast.component.html | 9 +- src/modules/toast/toast.component.scss | 27 +++++- src/modules/toast/toast.module.ts | 5 +- src/modules/toast/toast.service.ts | 83 +++++++++---------- src/modules/toast/types/index.ts | 3 + src/modules/toast/types/toast-config.ts | 8 ++ src/modules/toast/types/toast-message-type.ts | 6 ++ src/modules/toast/types/toast-message.ts | 34 ++++++++ 10 files changed, 154 insertions(+), 52 deletions(-) create mode 100644 src/modules/toast/toast-adapter.service.ts create mode 100644 src/modules/toast/types/index.ts create mode 100644 src/modules/toast/types/toast-config.ts create mode 100644 src/modules/toast/types/toast-message-type.ts create mode 100644 src/modules/toast/types/toast-message.ts diff --git a/src/demos/toast/toast-demo.component.html b/src/demos/toast/toast-demo.component.html index 79391e907..5c4c2373a 100644 --- a/src/demos/toast/toast-demo.component.html +++ b/src/demos/toast/toast-demo.component.html @@ -1,4 +1,3 @@
-
\ No newline at end of file diff --git a/src/modules/toast/toast-adapter.service.ts b/src/modules/toast/toast-adapter.service.ts new file mode 100644 index 000000000..76c7a5abf --- /dev/null +++ b/src/modules/toast/toast-adapter.service.ts @@ -0,0 +1,30 @@ +import { + Injectable, + Renderer2, + RendererFactory2 + } from '@angular/core'; + + import { SkyWindowRefService } from '../window'; + + @Injectable() + export class SkyToastAdapterService { + private renderer: Renderer2; + + constructor( + private rendererFactory: RendererFactory2, + private windowRef: SkyWindowRefService + ) { + this.renderer = this.rendererFactory.createRenderer(undefined, undefined); + } + + public appendToBody(element: any): void { + const body = this.windowRef.getWindow().document.body; + this.renderer.appendChild(body, element); + } + + public removeHostElement(): void { + const document = this.windowRef.getWindow().document; + const hostElement = document.querySelector('sky-toast'); + this.renderer.removeChild(document.body, hostElement); + } +} \ No newline at end of file diff --git a/src/modules/toast/toast.component.html b/src/modules/toast/toast.component.html index e1a317b01..a95600673 100644 --- a/src/modules/toast/toast.component.html +++ b/src/modules/toast/toast.component.html @@ -4,8 +4,13 @@ [ngClass]="{'sky-toast-info': message.toastType=='info', 'sky-toast-warning': message.toastType=='warning', 'sky-toast-danger': message.toastType=='danger', - 'sky-toast-success': message.toastType=='success'}"> -
{{message.message}}
+ 'sky-toast-success': message.toastType=='success', + 'sky-toast-closing': message.isClosing | async}"> +
+ {{message.message}} +
+ \ No newline at end of file From ce8ba629fccb00e0708f212d06143eb840c9f4f1 Mon Sep 17 00:00:00 2001 From: Conor Wright Date: Wed, 11 Apr 2018 09:56:09 -0400 Subject: [PATCH 10/46] fleshed out an initial structure for templated toasts --- src/demos/toast/toast-demo.component.html | 2 ++ src/demos/toast/toast-demo.component.ts | 10 +++++- src/modules/toast/index.ts | 2 +- .../toast/toast-container.component.html | 3 ++ .../toast/toast-container.component.scss | 16 +++++++++ ...ponent.ts => toast-container.component.ts} | 8 ++--- src/modules/toast/toast-messages/index.ts | 1 + .../toast-messages/toast-custom.directive.ts | 8 +++++ .../toast/toast-messages/toast.component.html | 22 ++++++++++++ .../{ => toast-messages}/toast.component.scss | 34 +++++------------- .../toast/toast-messages/toast.component.ts | 36 +++++++++++++++++++ src/modules/toast/toast.component.html | 24 ------------- src/modules/toast/toast.module.ts | 6 +++- src/modules/toast/toast.service.ts | 30 +++++++++++----- src/modules/toast/types/index.ts | 1 + src/modules/toast/types/toast-config.ts | 2 ++ src/modules/toast/types/toast-custom.ts | 5 +++ src/modules/toast/types/toast-message.ts | 9 ++--- 18 files changed, 150 insertions(+), 69 deletions(-) create mode 100644 src/modules/toast/toast-container.component.html create mode 100644 src/modules/toast/toast-container.component.scss rename src/modules/toast/{toast.component.ts => toast-container.component.ts} (61%) create mode 100644 src/modules/toast/toast-messages/index.ts create mode 100644 src/modules/toast/toast-messages/toast-custom.directive.ts create mode 100644 src/modules/toast/toast-messages/toast.component.html rename src/modules/toast/{ => toast-messages}/toast.component.scss (82%) create mode 100644 src/modules/toast/toast-messages/toast.component.ts delete mode 100644 src/modules/toast/toast.component.html create mode 100644 src/modules/toast/types/toast-custom.ts diff --git a/src/demos/toast/toast-demo.component.html b/src/demos/toast/toast-demo.component.html index 5e74a5d80..de5e3d35c 100644 --- a/src/demos/toast/toast-demo.component.html +++ b/src/demos/toast/toast-demo.component.html @@ -1,3 +1,5 @@
+ +
\ No newline at end of file diff --git a/src/demos/toast/toast-demo.component.ts b/src/demos/toast/toast-demo.component.ts index 00a0b75b4..2c77875f3 100644 --- a/src/demos/toast/toast-demo.component.ts +++ b/src/demos/toast/toast-demo.component.ts @@ -12,6 +12,14 @@ export class SkyToastDemoComponent { constructor(private toastSvc: SkyToastService) { } public openMessage() { - this.toastSvc.openMessage("Bananas aren't shoes"); + this.toastSvc.openMessage("This is a toast that lasts 10 seconds."); + } + + public openPersistentMessage() { + this.toastSvc.open({message: 'This toast has no timeout.', disableTimeout: true}); + } + + public openTemplatedMessage() { + this.toastSvc.openMessage('This toast has no timeout.', {disableTimeout: true}); } } diff --git a/src/modules/toast/index.ts b/src/modules/toast/index.ts index cde4e0f1d..ea6f6f22e 100644 --- a/src/modules/toast/index.ts +++ b/src/modules/toast/index.ts @@ -1,3 +1,3 @@ -export { SkyToastComponent } from './toast.component'; +export { SkyToastContainerComponent } from './toast-container.component'; export { SkyToastService } from './toast.service'; export { SkyToastModule } from './toast.module'; diff --git a/src/modules/toast/toast-container.component.html b/src/modules/toast/toast-container.component.html new file mode 100644 index 000000000..fded04660 --- /dev/null +++ b/src/modules/toast/toast-container.component.html @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/src/modules/toast/toast-container.component.scss b/src/modules/toast/toast-container.component.scss new file mode 100644 index 000000000..7c7851b80 --- /dev/null +++ b/src/modules/toast/toast-container.component.scss @@ -0,0 +1,16 @@ +@import "../../scss/variables"; + +.sky-toaster { + bottom: 0; + right: 0; + display: block; + position: fixed; + padding-bottom: $sky-margin-double; + padding-right: $sky-margin-double; + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Chrom and Opera */ +} \ No newline at end of file diff --git a/src/modules/toast/toast.component.ts b/src/modules/toast/toast-container.component.ts similarity index 61% rename from src/modules/toast/toast.component.ts rename to src/modules/toast/toast-container.component.ts index eba9c4676..987fbc01b 100644 --- a/src/modules/toast/toast.component.ts +++ b/src/modules/toast/toast-container.component.ts @@ -3,11 +3,11 @@ import { SkyToastService } from './toast.service'; import { Observable } from 'rxjs/Observable'; @Component({ - selector: 'sky-toast', - templateUrl: './toast.component.html', - styleUrls: ['./toast.component.scss'], + selector: 'sky-toast-container', + templateUrl: './toast-container.component.html', + styleUrls: ['./toast-container.component.scss'], }) -export class SkyToastComponent implements OnInit { +export class SkyToastContainerComponent implements OnInit { messages: Observable; diff --git a/src/modules/toast/toast-messages/index.ts b/src/modules/toast/toast-messages/index.ts new file mode 100644 index 000000000..21d95348e --- /dev/null +++ b/src/modules/toast/toast-messages/index.ts @@ -0,0 +1 @@ +export * from './toast-custom.directive'; \ No newline at end of file diff --git a/src/modules/toast/toast-messages/toast-custom.directive.ts b/src/modules/toast/toast-messages/toast-custom.directive.ts new file mode 100644 index 000000000..54f15cde7 --- /dev/null +++ b/src/modules/toast/toast-messages/toast-custom.directive.ts @@ -0,0 +1,8 @@ +import { Directive, ViewContainerRef } from '@angular/core'; + +@Directive({ + selector: '[sky-toast-custom]' +}) +export class SkyCustomToastDirective { + constructor(public viewContainerRef: ViewContainerRef) {} +} \ No newline at end of file diff --git a/src/modules/toast/toast-messages/toast.component.html b/src/modules/toast/toast-messages/toast.component.html new file mode 100644 index 000000000..c154dbb4d --- /dev/null +++ b/src/modules/toast/toast-messages/toast.component.html @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/src/modules/toast/toast.component.scss b/src/modules/toast/toast-messages/toast.component.scss similarity index 82% rename from src/modules/toast/toast.component.scss rename to src/modules/toast/toast-messages/toast.component.scss index 880a19f22..9c8243b27 100644 --- a/src/modules/toast/toast.component.scss +++ b/src/modules/toast/toast-messages/toast.component.scss @@ -1,19 +1,4 @@ -@import "../../scss/variables"; - -.sky-toaster { - bottom: 0; - right: 0; - display: block; - position: fixed; - padding-bottom: $sky-margin-double; - padding-right: $sky-margin-double; - -webkit-touch-callout: none; /* iOS Safari */ - -webkit-user-select: none; /* Safari */ - -khtml-user-select: none; /* Konqueror HTML */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* Internet Explorer/Edge */ - user-select: none; /* Chrom and Opera */ -} +@import "../../../scss/variables"; .sky-toast { padding: 0 $sky-padding; @@ -27,6 +12,13 @@ opacity: 1; cursor: pointer; + &:hover { + -webkit-box-shadow:0 0 8px rgba(0,0,0,.40); + -moz-box-shadow:0 0 8px rgba(0,0,0,.40); + -o-box-shadow:0 0 8px rgba(0,0,0,.40); + box-shadow:0 0 8px rgba(0,0,0,.40); + } + .sky-toast-content { padding-top: $sky-padding; padding-bottom: $sky-padding; @@ -49,14 +41,6 @@ } } -.sky-toast:hover { - -webkit-box-shadow:0 0 8px rgba(0,0,0,.40); - -moz-box-shadow:0 0 8px rgba(0,0,0,.40); - -o-box-shadow:0 0 8px rgba(0,0,0,.40); - box-shadow:0 0 8px rgba(0,0,0,.40); -} - - .sky-toast-closing { opacity: 0; -webkit-transition: opacity linear 0.5s; @@ -133,4 +117,4 @@ &:hover { opacity: 1.0; } -} +} \ No newline at end of file diff --git a/src/modules/toast/toast-messages/toast.component.ts b/src/modules/toast/toast-messages/toast.component.ts new file mode 100644 index 000000000..2a01a9d17 --- /dev/null +++ b/src/modules/toast/toast-messages/toast.component.ts @@ -0,0 +1,36 @@ +import { Component, Input, ComponentFactoryResolver, OnInit, ViewChild } from '@angular/core'; +import { SkyToastMessage, SkyToastCustomComponent } from '../types'; +import { SkyCustomToastDirective } from '.'; + +@Component({ + selector: 'sky-toast', + templateUrl: './toast.component.html', + styleUrls: ['./toast.component.scss'], +}) +export class SkyToastComponent implements OnInit { + @Input('message') + public message: SkyToastMessage; + + @ViewChild(SkyCustomToastDirective) + private customToastHost: SkyCustomToastDirective; + + constructor( + private resolver: ComponentFactoryResolver + ) { } + + public ngOnInit() { + if (this.message.customComponentType) { + this.loadComponent(); + } + } + + private loadComponent() { + let componentFactory = this.resolver.resolveComponentFactory(this.message.customComponentType); + + let viewContainerRef = this.customToastHost.viewContainerRef; + viewContainerRef.clear(); + + let componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).message = this.message; + } +} \ No newline at end of file diff --git a/src/modules/toast/toast.component.html b/src/modules/toast/toast.component.html deleted file mode 100644 index a95600673..000000000 --- a/src/modules/toast/toast.component.html +++ /dev/null @@ -1,24 +0,0 @@ -
- -
\ No newline at end of file diff --git a/src/modules/toast/toast.module.ts b/src/modules/toast/toast.module.ts index fa8895338..716b22666 100644 --- a/src/modules/toast/toast.module.ts +++ b/src/modules/toast/toast.module.ts @@ -1,20 +1,23 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SkyToastService } from './toast.service'; -import { SkyToastComponent } from './toast.component'; +import { SkyToastContainerComponent } from './toast-container.component'; import { SkyResourcesModule } from '../resources'; import { SkyToastAdapterService } from './toast-adapter.service'; +import { SkyToastComponent } from './toast-messages/toast.component'; export { SkyToastService } @NgModule({ declarations: [ + SkyToastContainerComponent, SkyToastComponent ], imports: [ CommonModule, SkyResourcesModule ], exports: [ + SkyToastContainerComponent, SkyToastComponent ], providers: [ @@ -22,6 +25,7 @@ export { SkyToastService } SkyToastAdapterService ], entryComponents: [ + SkyToastContainerComponent, SkyToastComponent ] }) diff --git a/src/modules/toast/toast.service.ts b/src/modules/toast/toast.service.ts index 67ea50765..91bfdd4cb 100644 --- a/src/modules/toast/toast.service.ts +++ b/src/modules/toast/toast.service.ts @@ -1,13 +1,13 @@ -import { Injectable, ComponentRef, ComponentFactoryResolver, Injector, ApplicationRef, EmbeddedViewRef } from '@angular/core'; +import { Injectable, ComponentRef, ComponentFactoryResolver, Injector, ApplicationRef, EmbeddedViewRef, OnDestroy } from '@angular/core'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { Observable } from 'rxjs/Observable'; -import { SkyToastComponent } from './toast.component'; +import { SkyToastContainerComponent } from './toast-container.component'; import { SkyToastAdapterService } from './toast-adapter.service'; import { SkyToastMessage, ToastConfig, SkyToastType } from './types'; @Injectable() -export class SkyToastService { - private host: ComponentRef; +export class SkyToastService implements OnDestroy { + private host: ComponentRef; private _messages: SkyToastMessage[] = []; private _messageList: BehaviorSubject = new BehaviorSubject([]); @@ -36,6 +36,15 @@ export class SkyToastService { return message; } + public ngOnDestroy() { + this.host = undefined; + this._messages.forEach(message => { + message.close(); + }); + this._messageList.next([]); + this.adapter.removeHostElement(); + } + private removeFromQueue: Function = (message: SkyToastMessage) => { if (this._messages.length == 0) { throw 'The supplied message is not active.'; @@ -50,8 +59,11 @@ export class SkyToastService { }; private createMessage(config: ToastConfig): SkyToastMessage { - if (!config.message) { - throw 'A message must be provided.'; + if (!config.message && !config.customComponentType) { + throw 'Either a message or custom toast type must be provided.'; + } + if (config.message && config.customComponentType) { + throw 'Both a message and custom toast type may not be provided.'; } let timeout: number; @@ -72,12 +84,12 @@ export class SkyToastService { break; } - return new SkyToastMessage(config.message, toastType, this.removeFromQueue, timeout); + return new SkyToastMessage(config.message, config.customComponentType, toastType, this.removeFromQueue, timeout); } - private createHostComponent(): ComponentRef { + private createHostComponent(): ComponentRef { const componentRef = this.resolver - .resolveComponentFactory(SkyToastComponent) + .resolveComponentFactory(SkyToastContainerComponent) .create(this.injector); const domElem = (componentRef.hostView as EmbeddedViewRef).rootNodes[0]; diff --git a/src/modules/toast/types/index.ts b/src/modules/toast/types/index.ts index aae795230..0f189635e 100644 --- a/src/modules/toast/types/index.ts +++ b/src/modules/toast/types/index.ts @@ -1,3 +1,4 @@ export * from './toast-config'; +export * from './toast-custom'; export * from './toast-message'; export * from './toast-message-type'; diff --git a/src/modules/toast/types/toast-config.ts b/src/modules/toast/types/toast-config.ts index 52d578fac..9a533c8e4 100644 --- a/src/modules/toast/types/toast-config.ts +++ b/src/modules/toast/types/toast-config.ts @@ -1,7 +1,9 @@ import { SkyToastType } from './toast-message-type'; +import { Type } from '@angular/core'; export interface ToastConfig { message?: string, + customComponentType?: Type, disableTimeout?: boolean, timeout?: number, toastType?: SkyToastType diff --git a/src/modules/toast/types/toast-custom.ts b/src/modules/toast/types/toast-custom.ts new file mode 100644 index 000000000..a46c5da12 --- /dev/null +++ b/src/modules/toast/types/toast-custom.ts @@ -0,0 +1,5 @@ +import { SkyToastMessage } from "./toast-message"; + +export interface SkyToastCustomComponent { + message: SkyToastMessage +} \ No newline at end of file diff --git a/src/modules/toast/types/toast-message.ts b/src/modules/toast/types/toast-message.ts index 76a47c263..3302c0f9e 100644 --- a/src/modules/toast/types/toast-message.ts +++ b/src/modules/toast/types/toast-message.ts @@ -1,15 +1,16 @@ -import { SkyToastMessageType } from './toast-message-type'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { Observable } from 'rxjs/Observable'; +import { Type } from '@angular/core'; export class SkyToastMessage { public timeout?: NodeJS.Timer; - private _isClosed: BehaviorSubject; - private _isClosing: BehaviorSubject; public isClosed: Observable; public isClosing: Observable; - constructor(public message: string, public toastType: string, private removeFromQueue: Function, timeout?: number) { + private _isClosed: BehaviorSubject; + private _isClosing: BehaviorSubject; + + constructor(public message: string, public customComponentType: Type, public toastType: string, private removeFromQueue: Function, timeout?: number) { this._isClosed = new BehaviorSubject(false); this._isClosing = new BehaviorSubject(false); this.isClosed = this._isClosed.asObservable(); From bc3718792241ee833510bfa7c5ca5726272f2aab Mon Sep 17 00:00:00 2001 From: Conor Wright Date: Wed, 11 Apr 2018 14:03:54 -0400 Subject: [PATCH 11/46] implemented templated toast demo --- src/demo.ts | 2 ++ src/demos/toast/index.ts | 1 + .../toast-custom-demo.component.html | 3 +++ .../toast-custom-demo.component.scss | 6 +++++ .../toast-custom-demo.component.ts | 22 +++++++++++++++++++ src/demos/toast/toast-demo.component.ts | 5 +++-- src/demos/toast/toast-demo.module.ts | 0 src/modules/toast/toast-messages/index.ts | 3 ++- .../toast/toast-messages/toast.component.html | 6 ++--- .../toast/toast-messages/toast.component.ts | 1 + src/modules/toast/toast.module.ts | 14 +++++++----- src/modules/toast/toast.service.ts | 9 ++++++-- 12 files changed, 58 insertions(+), 14 deletions(-) create mode 100644 src/demos/toast/toast-custom/toast-custom-demo.component.html create mode 100644 src/demos/toast/toast-custom/toast-custom-demo.component.scss create mode 100644 src/demos/toast/toast-custom/toast-custom-demo.component.ts create mode 100644 src/demos/toast/toast-demo.module.ts diff --git a/src/demo.ts b/src/demo.ts index 2685f5ce3..c943091cc 100644 --- a/src/demo.ts +++ b/src/demo.ts @@ -70,6 +70,7 @@ import { SkyTileDemoComponent, SkyTimepickerDemoComponent, SkyToastDemoComponent, + SkyToastCustomDemoComponent, SkyTokensDemoComponent, SkyToolbarDemoComponent, SkyUrlValidationDemoComponent, @@ -149,6 +150,7 @@ const components = [ SkyTileDemoComponent, SkyTimepickerDemoComponent, SkyToastDemoComponent, + SkyToastCustomDemoComponent, SkyTokensDemoComponent, SkyToolbarDemoComponent, SkyUrlValidationDemoComponent, diff --git a/src/demos/toast/index.ts b/src/demos/toast/index.ts index 451957a7a..e91575fdd 100644 --- a/src/demos/toast/index.ts +++ b/src/demos/toast/index.ts @@ -1 +1,2 @@ export * from './toast-demo.component'; +export * from './toast-custom/toast-custom-demo.component'; \ No newline at end of file diff --git a/src/demos/toast/toast-custom/toast-custom-demo.component.html b/src/demos/toast/toast-custom/toast-custom-demo.component.html new file mode 100644 index 000000000..b1a90ed29 --- /dev/null +++ b/src/demos/toast/toast-custom/toast-custom-demo.component.html @@ -0,0 +1,3 @@ +
+ {{text}} +
\ No newline at end of file diff --git a/src/demos/toast/toast-custom/toast-custom-demo.component.scss b/src/demos/toast/toast-custom/toast-custom-demo.component.scss new file mode 100644 index 000000000..3bc6686ef --- /dev/null +++ b/src/demos/toast/toast-custom/toast-custom-demo.component.scss @@ -0,0 +1,6 @@ +@import "../../../scss/variables"; + +.sky-toast-demo-pinky { + background-color: pink; + border-color: rgb(209, 92, 137); +} \ No newline at end of file diff --git a/src/demos/toast/toast-custom/toast-custom-demo.component.ts b/src/demos/toast/toast-custom/toast-custom-demo.component.ts new file mode 100644 index 000000000..2bc9a5250 --- /dev/null +++ b/src/demos/toast/toast-custom/toast-custom-demo.component.ts @@ -0,0 +1,22 @@ +import { Component, OnInit } from '@angular/core'; +import { SkyToastCustomComponent, SkyToastMessage } from '../../../modules/toast/toast.module'; + +@Component({ + selector: 'sky-toast-custom-demo', + templateUrl: './toast-custom-demo.component.html', + styleUrls: ['./toast-custom-demo.component.scss'], +}) +export class SkyToastCustomDemoComponent implements OnInit, SkyToastCustomComponent { + public message: SkyToastMessage; + public text: string = 'This is a templated message. Look how pink it is!' + + constructor() {} + + public ngOnInit() { + this.message.isClosing.subscribe((value: boolean) => { + if (value) { + this.text = 'Bye bye :D'; + } + }); + } +} \ No newline at end of file diff --git a/src/demos/toast/toast-demo.component.ts b/src/demos/toast/toast-demo.component.ts index 2c77875f3..0be9cae6c 100644 --- a/src/demos/toast/toast-demo.component.ts +++ b/src/demos/toast/toast-demo.component.ts @@ -1,8 +1,9 @@ -import { Component } from '@angular/core'; +import { Component, Type } from '@angular/core'; import { SkyToastService } from '../../core'; +import { SkyToastCustomDemoComponent } from './toast-custom/toast-custom-demo.component'; @Component({ selector: 'sky-toast-demo', @@ -20,6 +21,6 @@ export class SkyToastDemoComponent { } public openTemplatedMessage() { - this.toastSvc.openMessage('This toast has no timeout.', {disableTimeout: true}); + this.toastSvc.openTemplatedMessage(SkyToastCustomDemoComponent, {disableTimeout: true}); } } diff --git a/src/demos/toast/toast-demo.module.ts b/src/demos/toast/toast-demo.module.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/modules/toast/toast-messages/index.ts b/src/modules/toast/toast-messages/index.ts index 21d95348e..8d6a60f15 100644 --- a/src/modules/toast/toast-messages/index.ts +++ b/src/modules/toast/toast-messages/index.ts @@ -1 +1,2 @@ -export * from './toast-custom.directive'; \ No newline at end of file +export * from './toast-custom.directive'; +export * from './toast.component'; \ No newline at end of file diff --git a/src/modules/toast/toast-messages/toast.component.html b/src/modules/toast/toast-messages/toast.component.html index c154dbb4d..919ef910e 100644 --- a/src/modules/toast/toast-messages/toast.component.html +++ b/src/modules/toast/toast-messages/toast.component.html @@ -1,6 +1,5 @@ diff --git a/src/modules/toast/toast-messages/toast.component.scss b/src/modules/toast/toast-messages/toast.component.scss index aad54a850..8e88489bd 100644 --- a/src/modules/toast/toast-messages/toast.component.scss +++ b/src/modules/toast/toast-messages/toast.component.scss @@ -1,4 +1,4 @@ -@import "../../../scss/variables"; +@import '../../../scss/variables'; .sky-toast { padding: 0 $sky-padding; @@ -23,7 +23,7 @@ padding-top: $sky-padding; padding-bottom: $sky-padding; width: 100%; - + ::ng-deep a { color: change-color($sky-text-color-default, $alpha: 0.8); text-decoration: underline; @@ -32,7 +32,7 @@ color: $sky-text-color-default; } } - + .sky-toast-content-message { margin: 0; } @@ -121,4 +121,4 @@ &:hover { opacity: 1.0; } -} \ No newline at end of file +} diff --git a/src/modules/toast/toast-messages/toast.component.ts b/src/modules/toast/toast-messages/toast.component.ts index d22650e88..3c38b63c2 100644 --- a/src/modules/toast/toast-messages/toast.component.ts +++ b/src/modules/toast/toast-messages/toast.component.ts @@ -1,14 +1,14 @@ import { - Component, - Input, - ComponentFactoryResolver, - OnInit, - ViewChild, - OnDestroy, - ViewContainerRef, - ReflectiveInjector, - ComponentRef, - Injector + Component, + Input, + ComponentFactoryResolver, + OnInit, + ViewChild, + OnDestroy, + ViewContainerRef, + ReflectiveInjector, + ComponentRef, + Injector } from '@angular/core'; import { SkyToastMessage, SkyToastCustomComponent } from '../types'; @@ -18,40 +18,40 @@ import { SkyToastMessage, SkyToastCustomComponent } from '../types'; styleUrls: ['./toast.component.scss'] }) export class SkyToastComponent implements OnInit, OnDestroy { - @Input('message') - public message: SkyToastMessage; + @Input('message') + public message: SkyToastMessage; - @ViewChild('skytoastcustomtemplate', { read: ViewContainerRef }) - private customToastHost: ViewContainerRef; + @ViewChild('skytoastcustomtemplate', { read: ViewContainerRef }) + private customToastHost: ViewContainerRef; - private customComponent: ComponentRef; + private customComponent: ComponentRef; - constructor( - private resolver: ComponentFactoryResolver, - private injector: Injector - ) {} + constructor( + private resolver: ComponentFactoryResolver, + private injector: Injector + ) {} - public ngOnInit() { - if (this.message.customComponentType) { - this.loadComponent(); - } + public ngOnInit() { + if (this.message.customComponentType) { + this.loadComponent(); } + } - public ngOnDestroy() { - if (this.customComponent) { - this.customComponent.destroy(); - } + public ngOnDestroy() { + if (this.customComponent) { + this.customComponent.destroy(); } + } - private loadComponent() { - this.customToastHost.clear(); + private loadComponent() { + this.customToastHost.clear(); - let componentFactory = this.resolver.resolveComponentFactory(this.message.customComponentType); - let providers = ReflectiveInjector.resolve(this.message.providers || []); + let componentFactory = this.resolver.resolveComponentFactory(this.message.customComponentType); + let providers = ReflectiveInjector.resolve(this.message.providers || []); - let injector = ReflectiveInjector.fromResolvedProviders(providers, this.injector); + let injector = ReflectiveInjector.fromResolvedProviders(providers, this.injector); - this.customComponent = this.customToastHost.createComponent(componentFactory, undefined, injector); - this.customComponent.instance.message = this.message; - } + this.customComponent = this.customToastHost.createComponent(componentFactory, undefined, injector); + this.customComponent.instance.message = this.message; + } } diff --git a/src/modules/toast/toast.module.ts b/src/modules/toast/toast.module.ts index b4a1583f8..4d40f013e 100644 --- a/src/modules/toast/toast.module.ts +++ b/src/modules/toast/toast.module.ts @@ -5,8 +5,8 @@ import { SkyToastContainerComponent } from './toast-container.component'; import { SkyResourcesModule } from '../resources'; import { SkyToastAdapterService } from './services/toast-adapter.service'; import { SkyToastComponent } from './toast-messages'; -export { SkyToastMessage, SkyToastCustomComponent } from './types'; +export { SkyToastMessage, SkyToastCustomComponent } from './types'; export { SkyToastService }; @NgModule({ diff --git a/src/modules/toast/types/toast-custom.ts b/src/modules/toast/types/toast-custom.ts index 7c32f7496..c5dd23906 100644 --- a/src/modules/toast/types/toast-custom.ts +++ b/src/modules/toast/types/toast-custom.ts @@ -1,5 +1,5 @@ import { SkyToastMessage } from './toast-message'; export interface SkyToastCustomComponent { - message: SkyToastMessage; + message: SkyToastMessage; } From 874ef5884b12a6fe3dc09c3108590b74bc2c50a7 Mon Sep 17 00:00:00 2001 From: Conor Wright Date: Thu, 19 Apr 2018 12:41:38 -0400 Subject: [PATCH 22/46] Switched to using sky-shadow on hover of toasts --- src/modules/toast/toast-messages/toast.component.scss | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/modules/toast/toast-messages/toast.component.scss b/src/modules/toast/toast-messages/toast.component.scss index 8e88489bd..7260d20fa 100644 --- a/src/modules/toast/toast-messages/toast.component.scss +++ b/src/modules/toast/toast-messages/toast.component.scss @@ -1,4 +1,5 @@ @import '../../../scss/variables'; +@import "../../../scss/mixins"; .sky-toast { padding: 0 $sky-padding; @@ -13,10 +14,7 @@ cursor: pointer; &:hover { - -webkit-box-shadow:0 0 8px rgba(0,0,0,.40); - -moz-box-shadow:0 0 8px rgba(0,0,0,.40); - -o-box-shadow:0 0 8px rgba(0,0,0,.40); - box-shadow:0 0 8px rgba(0,0,0,.40); + @include sky-shadow; } .sky-toast-content { From f57ffc0ac643837dcf5d0d94de12940c07dc67a6 Mon Sep 17 00:00:00 2001 From: Conor Wright Date: Tue, 24 Apr 2018 14:24:11 -0400 Subject: [PATCH 23/46] fixed styling issues that came from inf scroll PR --- .../src/app/toast/toast-demo.component.ts | 6 ++++- .../src/app/toast/toast-visual.component.html | 8 ++++--- .../src/app/toast/toast.visual-spec.ts | 5 +++- .../toast/toast-custom-demo.component.ts | 12 +++++++--- src/demos/toast/toast-demo.component.html | 18 ++++++++++++--- src/demos/toast/toast-demo.component.ts | 4 ++-- .../toast/services/toast.service.spec.ts | 13 +++++++++-- src/modules/toast/services/toast.service.ts | 22 +++++++++++------- .../toast/toast-container.component.html | 7 ++++-- .../toast/toast-container.component.spec.ts | 5 +++- .../toast/toast-container.component.ts | 5 +++- .../toast/toast-messages/toast.component.html | 23 ++++++++++++------- .../toast-messages/toast.component.spec.ts | 10 ++++++-- .../toast/toast-messages/toast.component.ts | 5 +++- src/modules/toast/toast.module.ts | 5 +++- src/modules/toast/types/toast-config.ts | 5 +++- src/modules/toast/types/toast-message.ts | 14 ++++++----- 17 files changed, 121 insertions(+), 46 deletions(-) diff --git a/skyux-spa-visual-tests/src/app/toast/toast-demo.component.ts b/skyux-spa-visual-tests/src/app/toast/toast-demo.component.ts index 4eb3c4233..e2f14f1ff 100644 --- a/skyux-spa-visual-tests/src/app/toast/toast-demo.component.ts +++ b/skyux-spa-visual-tests/src/app/toast/toast-demo.component.ts @@ -1,5 +1,9 @@ import { Component } from '@angular/core'; -import { SkyToastService, SkyToastCustomComponent, SkyToastMessage } from '@blackbaud/skyux/dist/core'; +import { + SkyToastService, + SkyToastCustomComponent, + SkyToastMessage +} from '@blackbaud/skyux/dist/core'; @Component({ selector: 'sky-test-cmp-toast', diff --git a/skyux-spa-visual-tests/src/app/toast/toast-visual.component.html b/skyux-spa-visual-tests/src/app/toast/toast-visual.component.html index 2e8164b04..a6c5337d0 100644 --- a/skyux-spa-visual-tests/src/app/toast/toast-visual.component.html +++ b/skyux-spa-visual-tests/src/app/toast/toast-visual.component.html @@ -1,13 +1,15 @@ -
+
diff --git a/skyux-spa-visual-tests/src/app/toast/toast.visual-spec.ts b/skyux-spa-visual-tests/src/app/toast/toast.visual-spec.ts index 5b5b89ccd..da7a2ae2d 100644 --- a/skyux-spa-visual-tests/src/app/toast/toast.visual-spec.ts +++ b/skyux-spa-visual-tests/src/app/toast/toast.visual-spec.ts @@ -1,5 +1,8 @@ import { SkyVisualTest } from '../../../config/utils/visual-test-commands'; -import { element, by } from 'protractor'; +import { + element, + by +} from 'protractor'; describe('Toast', () => { it('should match previous toast screenshot', () => { diff --git a/src/demos/toast/toast-custom-demo.component.ts b/src/demos/toast/toast-custom-demo.component.ts index e7b4c33b4..1613a0de3 100644 --- a/src/demos/toast/toast-custom-demo.component.ts +++ b/src/demos/toast/toast-custom-demo.component.ts @@ -1,5 +1,11 @@ -import { Component, OnInit } from '@angular/core'; -import { SkyToastCustomComponent, SkyToastMessage } from '../../core'; +import { + Component, + OnInit +} from '@angular/core'; +import { + SkyToastCustomComponent, + SkyToastMessage +} from '../../core'; @Component({ selector: 'sky-toast-custom-demo', @@ -7,7 +13,7 @@ import { SkyToastCustomComponent, SkyToastMessage } from '../../core'; }) export class SkyToastCustomDemoComponent implements OnInit, SkyToastCustomComponent { public message: SkyToastMessage; - public text: string = 'This is a templated message. It can even link you to '; + public text = 'This is a templated message. It can even link you to '; constructor() {} diff --git a/src/demos/toast/toast-demo.component.html b/src/demos/toast/toast-demo.component.html index c046dab5e..c3b8d6127 100644 --- a/src/demos/toast/toast-demo.component.html +++ b/src/demos/toast/toast-demo.component.html @@ -8,11 +8,23 @@ {{ typeTranslator[type] }} - + - - + +
diff --git a/src/demos/toast/toast-demo.component.ts b/src/demos/toast/toast-demo.component.ts index 7eb1e7275..c0687b411 100644 --- a/src/demos/toast/toast-demo.component.ts +++ b/src/demos/toast/toast-demo.component.ts @@ -10,9 +10,9 @@ import { SkyToastCustomDemoComponent } from './toast-custom-demo.component'; templateUrl: './toast-demo.component.html' }) export class SkyToastDemoComponent { + public selectedType = SkyToastType.Info; public typeTranslator = SkyToastType; - public types: SkyToastType[] = [SkyToastType.Info, SkyToastType.Success, SkyToastType.Warning, SkyToastType.Danger]; - public selectedType: SkyToastType = SkyToastType.Info; + public types = [SkyToastType.Info, SkyToastType.Success, SkyToastType.Warning, SkyToastType.Danger]; constructor(private toastSvc: SkyToastService) { } diff --git a/src/modules/toast/services/toast.service.spec.ts b/src/modules/toast/services/toast.service.spec.ts index a03aab2b5..ec240e2a8 100644 --- a/src/modules/toast/services/toast.service.spec.ts +++ b/src/modules/toast/services/toast.service.spec.ts @@ -1,9 +1,18 @@ import { TestBed } from '@angular/core/testing'; import { SkyToastService } from './toast.service'; -import { SkyToastConfig, SkyToastType, SkyToastMessage, SkyToastCustomComponent } from '../types'; +import { + SkyToastConfig, + SkyToastType, + SkyToastMessage, + SkyToastCustomComponent +} from '../types'; import { SkyWindowRefService } from '../../window'; import { SkyToastAdapterService } from './toast-adapter.service'; -import { ApplicationRef, ComponentFactoryResolver, Injector } from '@angular/core'; +import { + ApplicationRef, + ComponentFactoryResolver, + Injector +} from '@angular/core'; describe('Toast service', () => { class TestComponent implements SkyToastCustomComponent { public message: SkyToastMessage; } diff --git a/src/modules/toast/services/toast.service.ts b/src/modules/toast/services/toast.service.ts index 364d8269f..52c61e021 100644 --- a/src/modules/toast/services/toast.service.ts +++ b/src/modules/toast/services/toast.service.ts @@ -13,13 +13,18 @@ import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { Observable } from 'rxjs/Observable'; import { SkyToastContainerComponent } from '../toast-container.component'; import { SkyToastAdapterService } from './toast-adapter.service'; -import { SkyToastMessage, SkyToastConfig, SkyToastType, SkyToastCustomComponent } from '../types'; +import { + SkyToastMessage, + SkyToastConfig, + SkyToastType, + SkyToastCustomComponent +} from '../types'; @Injectable() export class SkyToastService implements OnDestroy { private host: ComponentRef; - private _messages: SkyToastMessage[] = []; + private messages: SkyToastMessage[] = []; private _messageList: BehaviorSubject = new BehaviorSubject([]); public get getMessages(): Observable { return this._messageList.asObservable(); } @@ -27,7 +32,8 @@ export class SkyToastService implements OnDestroy { private appRef: ApplicationRef, private injector: Injector, private resolver: ComponentFactoryResolver, - private adapter: SkyToastAdapterService) {} + private adapter: SkyToastAdapterService + ) {} public openMessage(message: string, config: SkyToastConfig = {}) { config.message = message; @@ -48,15 +54,15 @@ export class SkyToastService implements OnDestroy { } let message: SkyToastMessage = this.createMessage(config); - this._messages.push(message); - this._messageList.next(this._messages); + this.messages.push(message); + this._messageList.next(this.messages); return message; } public ngOnDestroy() { this.host = undefined; - this._messages.forEach(message => { + this.messages.forEach(message => { message.close(); }); this._messageList.next([]); @@ -64,8 +70,8 @@ export class SkyToastService implements OnDestroy { } private removeFromQueue: Function = (message: SkyToastMessage) => { - this._messages = this._messages.filter(msg => msg !== message); - this._messageList.next(this._messages); + this.messages = this.messages.filter(msg => msg !== message); + this._messageList.next(this.messages); } private createMessage(config: SkyToastConfig): SkyToastMessage { diff --git a/src/modules/toast/toast-container.component.html b/src/modules/toast/toast-container.component.html index fded04660..650a5d7eb 100644 --- a/src/modules/toast/toast-container.component.html +++ b/src/modules/toast/toast-container.component.html @@ -1,3 +1,6 @@
- -
\ No newline at end of file + + +
diff --git a/src/modules/toast/toast-container.component.spec.ts b/src/modules/toast/toast-container.component.spec.ts index 2f6cec047..791ab7a35 100644 --- a/src/modules/toast/toast-container.component.spec.ts +++ b/src/modules/toast/toast-container.component.spec.ts @@ -1,5 +1,8 @@ import { TestBed } from '@angular/core/testing'; -import { SkyToastService, SkyToastContainerComponent } from '.'; +import { + SkyToastService, + SkyToastContainerComponent +} from '.'; import { SkyToastMessage } from './types'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; diff --git a/src/modules/toast/toast-container.component.ts b/src/modules/toast/toast-container.component.ts index 9e9a16694..32355d6ef 100644 --- a/src/modules/toast/toast-container.component.ts +++ b/src/modules/toast/toast-container.component.ts @@ -1,4 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { + Component, + OnInit +} from '@angular/core'; import { SkyToastService } from './services/toast.service'; import { Observable } from 'rxjs/Observable'; diff --git a/src/modules/toast/toast-messages/toast.component.html b/src/modules/toast/toast-messages/toast.component.html index b55f74929..77f1ab8a8 100644 --- a/src/modules/toast/toast-messages/toast.component.html +++ b/src/modules/toast/toast-messages/toast.component.html @@ -1,22 +1,29 @@ diff --git a/src/modules/toast/toast-messages/toast.component.spec.ts b/src/modules/toast/toast-messages/toast.component.spec.ts index 778fd947a..46010b26c 100644 --- a/src/modules/toast/toast-messages/toast.component.spec.ts +++ b/src/modules/toast/toast-messages/toast.component.spec.ts @@ -1,7 +1,13 @@ import { TestBed } from '@angular/core/testing'; -import { SkyToastMessage, SkyToastCustomComponent } from '../types'; +import { + SkyToastMessage, + SkyToastCustomComponent +} from '../types'; import { SkyToastComponent } from '.'; -import { ComponentFactoryResolver, Injector } from '@angular/core'; +import { + ComponentFactoryResolver, + Injector +} from '@angular/core'; describe('Toast service', () => { class TestComponent implements SkyToastCustomComponent { public message: SkyToastMessage; } diff --git a/src/modules/toast/toast-messages/toast.component.ts b/src/modules/toast/toast-messages/toast.component.ts index 3c38b63c2..e068e716e 100644 --- a/src/modules/toast/toast-messages/toast.component.ts +++ b/src/modules/toast/toast-messages/toast.component.ts @@ -10,7 +10,10 @@ import { ComponentRef, Injector } from '@angular/core'; -import { SkyToastMessage, SkyToastCustomComponent } from '../types'; +import { + SkyToastMessage, + SkyToastCustomComponent +} from '../types'; @Component({ selector: 'sky-toast', diff --git a/src/modules/toast/toast.module.ts b/src/modules/toast/toast.module.ts index 4d40f013e..71fcdcf76 100644 --- a/src/modules/toast/toast.module.ts +++ b/src/modules/toast/toast.module.ts @@ -6,7 +6,10 @@ import { SkyResourcesModule } from '../resources'; import { SkyToastAdapterService } from './services/toast-adapter.service'; import { SkyToastComponent } from './toast-messages'; -export { SkyToastMessage, SkyToastCustomComponent } from './types'; +export { + SkyToastMessage, + SkyToastCustomComponent +} from './types'; export { SkyToastService }; @NgModule({ diff --git a/src/modules/toast/types/toast-config.ts b/src/modules/toast/types/toast-config.ts index 266549ebf..95b01362d 100644 --- a/src/modules/toast/types/toast-config.ts +++ b/src/modules/toast/types/toast-config.ts @@ -1,5 +1,8 @@ import { SkyToastType } from './toast-message-type'; -import { Type, Provider } from '@angular/core'; +import { + Type, + Provider +} from '@angular/core'; export interface SkyToastConfig { message?: string; diff --git a/src/modules/toast/types/toast-message.ts b/src/modules/toast/types/toast-message.ts index 7004847e4..ab139b480 100644 --- a/src/modules/toast/types/toast-message.ts +++ b/src/modules/toast/types/toast-message.ts @@ -1,14 +1,17 @@ import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { Observable } from 'rxjs/Observable'; -import { Type, Provider } from '@angular/core'; +import { + Type, + Provider +} from '@angular/core'; export class SkyToastMessage { - public isClosed: Observable; - public isClosing: Observable; - private _isClosed: BehaviorSubject; private _isClosing: BehaviorSubject; + public get isClosed(): Observable { return this._isClosed.asObservable(); } + public get isClosing(): Observable { return this._isClosing.asObservable(); } + constructor( public message: string, public customComponentType: Type, @@ -18,13 +21,12 @@ export class SkyToastMessage { ) { this._isClosed = new BehaviorSubject(false); this._isClosing = new BehaviorSubject(false); - this.isClosed = this._isClosed.asObservable(); - this.isClosing = this._isClosing.asObservable(); } public close = () => { if (!this._isClosing.getValue()) { this._isClosing.next(true); + setTimeout(() => { this.removeFromQueue(this); this._isClosed.next(true); From e548824e03e429f736b3ba3aae8f146f2f841039 Mon Sep 17 00:00:00 2001 From: Conor Wright Date: Wed, 25 Apr 2018 15:28:43 -0400 Subject: [PATCH 24/46] added unit testing for the toast adapter --- .../services/toast-adapter.service.spec.ts | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/modules/toast/services/toast-adapter.service.spec.ts diff --git a/src/modules/toast/services/toast-adapter.service.spec.ts b/src/modules/toast/services/toast-adapter.service.spec.ts new file mode 100644 index 000000000..4d7412e4b --- /dev/null +++ b/src/modules/toast/services/toast-adapter.service.spec.ts @@ -0,0 +1,43 @@ +import { TestBed } from '@angular/core/testing'; +import { SkyWindowRefService } from '../../window'; +import { RendererFactory2 } from '@angular/core'; +import { SkyToastAdapterService } from './toast-adapter.service'; + +describe('Toast adapter service', () => { + + let adapter: SkyToastAdapterService; + let rendererCallCounts = { + appendCalledCount: 0, + removeCalledCount: 0 + }; + + beforeEach(() => { + let rendererMock = { + appendChild: () => { rendererCallCounts.appendCalledCount++; }, + removeChild: () => { rendererCallCounts.removeCalledCount++; } + }; + TestBed.configureTestingModule({ + providers: [ + SkyToastAdapterService, + SkyWindowRefService, + { + provide: RendererFactory2, + useValue: { + createRenderer() { return rendererMock; } + } + } + ] + }); + adapter = TestBed.get(SkyToastAdapterService); + }); + + it('should append element to body', () => { + adapter.appendToBody(undefined); + expect(rendererCallCounts.appendCalledCount).toBe(1); + }); + + it('should remove element from body', () => { + adapter.removeHostElement(); + expect(rendererCallCounts.removeCalledCount).toBe(1); + }); +}); From c6c847b521ad56a4c7194e49480977aec50707ed Mon Sep 17 00:00:00 2001 From: Conor Wright Date: Mon, 30 Apr 2018 13:33:06 -0400 Subject: [PATCH 25/46] added aria-live and role attrs to toasts --- src/modules/toast/toast-container.component.html | 4 +++- src/modules/toast/toast-messages/toast.component.html | 11 ++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/modules/toast/toast-container.component.html b/src/modules/toast/toast-container.component.html index 650a5d7eb..71914d146 100644 --- a/src/modules/toast/toast-container.component.html +++ b/src/modules/toast/toast-container.component.html @@ -1,4 +1,6 @@ -
+