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

Toastr service and component #1614

Closed
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
3f4222e
Resolving Card action bar still visable after hiding with *ngIf #1421
blackbaud-conorwright Mar 7, 2018
a450054
Addressed PR style comments
blackbaud-conorwright Mar 8, 2018
4b809aa
Merge remote-tracking branch 'upstream/master'
blackbaud-conorwright Mar 9, 2018
d55f351
Merge branch 'master' into master
Blackbaud-SteveBrush Mar 9, 2018
833bcc7
Merge remote-tracking branch 'upstream/master'
blackbaud-conorwright Mar 12, 2018
b553659
Merge remote-tracking branch 'upstream/master'
blackbaud-conorwright Mar 15, 2018
ab82ba3
Merge remote-tracking branch 'upstream/master'
blackbaud-conorwright Mar 19, 2018
db21c76
Merge remote-tracking branch 'upstream/master'
blackbaud-conorwright Mar 27, 2018
a282a86
Merge remote-tracking branch 'upstream/master'
blackbaud-conorwright Mar 30, 2018
995f024
started porting over alert design to toast
blackbaud-conorwright Apr 3, 2018
f4c10f0
began working on toast component from scratch
blackbaud-conorwright Apr 4, 2018
c8994ae
got a base demo and toast service running
blackbaud-conorwright Apr 4, 2018
d210c2b
Merge remote-tracking branch 'upstream/master'
blackbaud-conorwright Apr 10, 2018
11ab289
Merge remote-tracking branch 'origin/master' into toastr-fromscratch
blackbaud-conorwright Apr 10, 2018
a49ebf3
Got the base toast service functional
blackbaud-conorwright Apr 10, 2018
28c09b6
moved the toaster to the bottom right
blackbaud-conorwright Apr 10, 2018
3b5d5cb
Steve's comments. Added fading close to toasts
blackbaud-conorwright Apr 10, 2018
35de170
styled the toast demo button
blackbaud-conorwright Apr 10, 2018
ce8ba62
fleshed out an initial structure for templated toasts
blackbaud-conorwright Apr 11, 2018
bc37187
implemented templated toast demo
blackbaud-conorwright Apr 11, 2018
82c286d
fixed hiding issue with templated toasts
blackbaud-conorwright Apr 11, 2018
52f7983
removed timeout. removed custom toast directive.
blackbaud-conorwright Apr 12, 2018
692cbf0
finished templating functionality.added types to demo
blackbaud-conorwright Apr 12, 2018
803a205
finished up the base set of unit testing
blackbaud-conorwright Apr 16, 2018
ed4558f
fixed import to target core.ts
blackbaud-conorwright Apr 17, 2018
35e789d
Merge remote-tracking branch 'upstream/master'
blackbaud-conorwright Apr 17, 2018
8c8f6c2
Merge remote-tracking branch 'origin/master' into toastr-fromscratch
blackbaud-conorwright Apr 17, 2018
a4f23b3
add visual tests for toast service
blackbaud-conorwright Apr 17, 2018
7d3458f
fixed style issues with toast component
blackbaud-conorwright Apr 17, 2018
03c63ae
expanded test coverage of the toast component
blackbaud-conorwright Apr 18, 2018
a37b829
fixed import issue for toastcontainer tests
blackbaud-conorwright Apr 18, 2018
99696ac
cleaned up based on style guide from steve in infinite scroll pr
blackbaud-conorwright Apr 19, 2018
874ef58
Switched to using sky-shadow on hover of toasts
blackbaud-conorwright Apr 19, 2018
636c5dd
Merge remote-tracking branch 'upstream/master'
blackbaud-conorwright Apr 23, 2018
0158250
Merge remote-tracking branch 'origin/master' into toastr-fromscratch
blackbaud-conorwright Apr 23, 2018
f57ffc0
fixed styling issues that came from inf scroll PR
blackbaud-conorwright Apr 24, 2018
e548824
added unit testing for the toast adapter
blackbaud-conorwright Apr 25, 2018
c6c847b
added aria-live and role attrs to toasts
blackbaud-conorwright Apr 30, 2018
bdc97a6
Merge remote-tracking branch 'upstream/master'
blackbaud-conorwright May 1, 2018
ff5093c
Merge remote-tracking branch 'origin/master' into toastr-fromscratch
blackbaud-conorwright May 1, 2018
83e7d04
Merge branch 'master' into toastr-fromscratch
Blackbaud-SteveBrush May 1, 2018
6104aaf
Merge remote-tracking branch 'upstream/master'
blackbaud-conorwright May 2, 2018
01c38d6
refactored toast design to address PR comments
blackbaud-conorwright May 3, 2018
2fa1e41
prettied up the demo a little
blackbaud-conorwright May 4, 2018
57bfe9c
updated for the remaining PR comments
blackbaud-conorwright May 4, 2018
6e766de
Merge branch 'master' into toastr-fromscratch
Blackbaud-SteveBrush May 7, 2018
d576545
refactored for PR comments
blackbaud-conorwright May 8, 2018
15103e0
Merge branch 'toastr-fromscratch' of github.com:blackbaud-conorwright…
blackbaud-conorwright May 8, 2018
37f50ec
Merge remote-tracking branch 'upstream/master'
blackbaud-conorwright May 8, 2018
ac1e7bd
Merge remote-tracking branch 'origin/master' into toastr-fromscratch
blackbaud-conorwright May 8, 2018
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
3 changes: 3 additions & 0 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -123,6 +124,7 @@ import { SkyWaitModule } from './modules/wait';
SkyTextHighlightModule,
SkyTilesModule,
SkyTimepickerModule,
SkyToastModule,
SkyTokensModule,
SkyToolbarModule,
SkyUrlValidationModule,
Expand Down Expand Up @@ -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';
Expand Down
2 changes: 2 additions & 0 deletions src/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ import {
SkyTextHighlightDemoComponent,
SkyTileDemoComponent,
SkyTimepickerDemoComponent,
SkyToastDemoComponent,
SkyTokensDemoComponent,
SkyToolbarDemoComponent,
SkyUrlValidationDemoComponent,
Expand Down Expand Up @@ -147,6 +148,7 @@ const components = [
SkyTextHighlightDemoComponent,
SkyTileDemoComponent,
SkyTimepickerDemoComponent,
SkyToastDemoComponent,
SkyTokensDemoComponent,
SkyToolbarDemoComponent,
SkyUrlValidationDemoComponent,
Expand Down
17 changes: 17 additions & 0 deletions src/demos/demo.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import {
SkyTextHighlightDemoComponent,
SkyTileDemoComponent,
SkyTimepickerDemoComponent,
SkyToastDemoComponent,
SkyTokensDemoComponent,
SkyToolbarDemoComponent,
SkyUrlValidationDemoComponent,
Expand Down Expand Up @@ -996,6 +997,22 @@ export class SkyDemoService {
}
]
},
{
name: 'Toast',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you missing the "custom" toast component here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

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,
Expand Down
1 change: 1 addition & 0 deletions src/demos/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
1 change: 1 addition & 0 deletions src/demos/toast/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './toast-demo.component';
4 changes: 4 additions & 0 deletions src/demos/toast/toast-demo.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div>
<button (click)='openMessage()'>Open toast</button>
<sky-toast></sky-toast>
</div>
17 changes: 17 additions & 0 deletions src/demos/toast/toast-demo.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Component } from '@angular/core';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs barrel import format.


import {
SkyToastService
} from '../../core';

@Component({
selector: 'sky-toast-demo',
templateUrl: './toast-demo.component.html'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs OnPush change detection strategy.

})
export class SkyToastDemoComponent {
constructor(private toastSvc: SkyToastService) { }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All constructor injections should be on a single line. #1647 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


public openMessage() {
this.toastSvc.openMessage("Bananas aren't shoes");
}
}
4 changes: 4 additions & 0 deletions src/locales/resources_en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,10 @@
"_description": "The close button for the timepicker modal",
"message": "Done"
},
"toast_close": {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's text for a button, I usually suffix the key with _button.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. Sorry missed that after applying the inf scroll changes from before

"_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"
Expand Down
3 changes: 3 additions & 0 deletions src/modules/toast/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { SkyToastComponent } from './toast.component';
export { SkyToastService } from './toast.service';
export { SkyToastModule } from './toast.module';
19 changes: 19 additions & 0 deletions src/modules/toast/toast.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<div class="sky-toaster">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great start, but we'll need to inject the Toast "host" component at the bottom of the page, just before the closing <body> tag, to make sure that they always appear outside the normal flow of the document. See how we did it with the Flyout component, as an example: https://github.com/blackbaud/skyux2/blob/master/src/modules/flyout/flyout.service.ts#L54-L65

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem to incorporate any assistive technology support from what I can see. Especially for the case where type=danger for error identification, but I think we should support this for all the type. This could be done an ARIA live region. It needs to be present in the DOM empty and then have content injected. See - https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions

For type=danger it would make sense to use aria-live="assertive" so this is read out immediately. While the other types would be aria-live="polite" which is more the intent for these to be not immediate/interruptive.
Another decent reference - https://www.w3.org/TR/WCAG20-TECHS/ARIA19.html

IBM's Carbon Design system notification component is a good example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Blackbaud-MattGregg
Alright, I've added an "alert" role to the toast container and aria-live attributes to the toasts based on if they are "danger" or not (polite versus assertive). It looks correct when I run it in NVDA, but is this sufficient or are there other concerns?

Sorry, I'm still not fully familiar with accessibility requirements, but I'm going through the learning videos right now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@blackbaud-conorwright that's great. If those things are in, it should be good to go from this accessibility perspective. thanks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sweet! Thank you 😄

<aside *ngFor="let message of messages | async">
<div class="sky-toast"
[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'}">
<div class='sky-toast-content'>{{message.message}}</div>
<button
type="button"
class="sky-toast-close"
(click)="message.close()"
[attr.aria-label]="'toast_close' | skyResources"
[hidden]="!true">
<span aria-hidden="true"><i class="fa fa-close"></i></span>
</button>
</div>
</aside>
</div>
113 changes: 113 additions & 0 deletions src/modules/toast/toast.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
@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;
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: block;

&:hover {
opacity: 1.0;
}
}
19 changes: 19 additions & 0 deletions src/modules/toast/toast.component.ts
Original file line number Diff line number Diff line change
@@ -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<any>;

constructor(private toast: SkyToastService) { }

ngOnInit() {
this.messages = this.toast.getMessages
}
}
26 changes: 26 additions & 0 deletions src/modules/toast/toast.module.ts
Original file line number Diff line number Diff line change
@@ -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 {
}
25 changes: 25 additions & 0 deletions src/modules/toast/toast.service.spec.ts
Original file line number Diff line number Diff line change
@@ -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]);
});
});
Loading