Skip to content
This repository has been archived by the owner on Dec 8, 2022. It is now read-only.

Commit

Permalink
fleshed out an initial structure for templated toasts
Browse files Browse the repository at this point in the history
  • Loading branch information
blackbaud-conorwright committed Apr 11, 2018
1 parent 35de170 commit ce8ba62
Show file tree
Hide file tree
Showing 18 changed files with 150 additions and 69 deletions.
2 changes: 2 additions & 0 deletions src/demos/toast/toast-demo.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<div>
<button class='sky-btn sky-btn-primary' (click)='openMessage()'>Open toast</button>
<button class='sky-btn sky-btn-primary' (click)='openPersistentMessage()'>Open persistent toast</button>
<button class='sky-btn sky-btn-primary' (click)='openTemplatedMessage()'>Open templated toast</button>
</div>
10 changes: 9 additions & 1 deletion src/demos/toast/toast-demo.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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});
}
}
2 changes: 1 addition & 1 deletion src/modules/toast/index.ts
Original file line number Diff line number Diff line change
@@ -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';
3 changes: 3 additions & 0 deletions src/modules/toast/toast-container.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="sky-toaster">
<sky-toast *ngFor="let message of messages | async" [message]="message"></sky-toast>
</div>
16 changes: 16 additions & 0 deletions src/modules/toast/toast-container.component.scss
Original file line number Diff line number Diff line change
@@ -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 */
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<any>;

Expand Down
1 change: 1 addition & 0 deletions src/modules/toast/toast-messages/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './toast-custom.directive';
8 changes: 8 additions & 0 deletions src/modules/toast/toast-messages/toast-custom.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
selector: '[sky-toast-custom]'
})
export class SkyCustomToastDirective {
constructor(public viewContainerRef: ViewContainerRef) {}
}
22 changes: 22 additions & 0 deletions src/modules/toast/toast-messages/toast.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<aside>
<ng-template sky-toast-custom *ngIf="message.componentRef"></ng-template>
<div class="sky-toast" *ngIf="!message.componentRef"
[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',
'sky-toast-closing': message.isClosing | async}">
<div
(click)="message.close()"
class='sky-toast-content'>
{{message.message}}
</div>
<button
type="button"
class="sky-toast-close"
(click)="message.close()"
[attr.aria-label]="'toast_close' | skyResources">
<span aria-hidden="true"><i class="fa fa-close"></i></span>
</button>
</div>
</aside>
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -133,4 +117,4 @@
&:hover {
opacity: 1.0;
}
}
}
36 changes: 36 additions & 0 deletions src/modules/toast/toast-messages/toast.component.ts
Original file line number Diff line number Diff line change
@@ -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);
(<SkyToastCustomComponent>componentRef.instance).message = this.message;
}
}
24 changes: 0 additions & 24 deletions src/modules/toast/toast.component.html

This file was deleted.

6 changes: 5 additions & 1 deletion src/modules/toast/toast.module.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
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: [
SkyToastService,
SkyToastAdapterService
],
entryComponents: [
SkyToastContainerComponent,
SkyToastComponent
]
})
Expand Down
30 changes: 21 additions & 9 deletions src/modules/toast/toast.service.ts
Original file line number Diff line number Diff line change
@@ -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<SkyToastComponent>;
export class SkyToastService implements OnDestroy {
private host: ComponentRef<SkyToastContainerComponent>;

private _messages: SkyToastMessage[] = [];
private _messageList: BehaviorSubject<SkyToastMessage[]> = new BehaviorSubject([]);
Expand Down Expand Up @@ -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.';
Expand All @@ -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;
Expand All @@ -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<SkyToastComponent> {
private createHostComponent(): ComponentRef<SkyToastContainerComponent> {
const componentRef = this.resolver
.resolveComponentFactory(SkyToastComponent)
.resolveComponentFactory(SkyToastContainerComponent)
.create(this.injector);

const domElem = (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0];
Expand Down
1 change: 1 addition & 0 deletions src/modules/toast/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './toast-config';
export * from './toast-custom';
export * from './toast-message';
export * from './toast-message-type';
2 changes: 2 additions & 0 deletions src/modules/toast/types/toast-config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { SkyToastType } from './toast-message-type';
import { Type } from '@angular/core';

export interface ToastConfig {
message?: string,
customComponentType?: Type<any>,
disableTimeout?: boolean,
timeout?: number,
toastType?: SkyToastType
Expand Down
5 changes: 5 additions & 0 deletions src/modules/toast/types/toast-custom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { SkyToastMessage } from "./toast-message";

export interface SkyToastCustomComponent {
message: SkyToastMessage
}
9 changes: 5 additions & 4 deletions src/modules/toast/types/toast-message.ts
Original file line number Diff line number Diff line change
@@ -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<boolean>;
private _isClosing: BehaviorSubject<boolean>;
public isClosed: Observable<boolean>;
public isClosing: Observable<boolean>;

constructor(public message: string, public toastType: string, private removeFromQueue: Function, timeout?: number) {
private _isClosed: BehaviorSubject<boolean>;
private _isClosing: BehaviorSubject<boolean>;

constructor(public message: string, public customComponentType: Type<any>, public toastType: string, private removeFromQueue: Function, timeout?: number) {
this._isClosed = new BehaviorSubject(false);
this._isClosing = new BehaviorSubject(false);
this.isClosed = this._isClosed.asObservable();
Expand Down

0 comments on commit ce8ba62

Please sign in to comment.