From 82adf6f3d36b236f12eb0b0bc1f170681f73bb24 Mon Sep 17 00:00:00 2001 From: Dan Bucholtz Date: Wed, 8 Jun 2016 10:54:31 -0500 Subject: [PATCH] Feature/toast position (#6804) * refactor(toast): refactored toast to support positions and clean up transitions a bit refactored toast to support positions and clean up transitions a bit * test(toast): added additional test added additional tests --- demos/toast/index.ts | 5 +- demos/toast/main.html | 4 +- src/components/toast/test/basic/index.ts | 5 +- src/components/toast/test/basic/main.html | 4 +- src/components/toast/test/toast.spec.ts | 38 +++- src/components/toast/toast.ios.scss | 30 +-- src/components/toast/toast.md.scss | 29 +-- src/components/toast/toast.scss | 15 -- src/components/toast/toast.ts | 231 ++++++++++++++++++---- src/components/toast/toast.wp.scss | 19 +- 10 files changed, 288 insertions(+), 92 deletions(-) diff --git a/demos/toast/index.ts b/demos/toast/index.ts index e18a1e0a8a..e55a7962bc 100644 --- a/demos/toast/index.ts +++ b/demos/toast/index.ts @@ -8,9 +8,11 @@ import {ionicBootstrap, Toast, NavController} from 'ionic-angular'; class ApiPage { constructor(private nav: NavController) { } - showToast() { + showToast(position: string) { const toast = Toast.create({ message: 'User was created successfully', + position: position, + duration: 3000 }); toast.onDismiss(this.dismissHandler); @@ -20,6 +22,7 @@ class ApiPage { showLongToast() { const toast = Toast.create({ message: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea voluptatibus quibusdam eum nihil optio, ullam accusamus magni, nobis suscipit reprehenderit, sequi quam amet impedit. Accusamus dolorem voluptates laborum dolor obcaecati.', + duration: 3000 }); toast.onDismiss(this.dismissHandler); diff --git a/demos/toast/main.html b/demos/toast/main.html index 42341c5178..c3dfa386eb 100644 --- a/demos/toast/main.html +++ b/demos/toast/main.html @@ -3,7 +3,9 @@ - + + + diff --git a/src/components/toast/test/basic/index.ts b/src/components/toast/test/basic/index.ts index 3454c70d38..ee863f9ec3 100644 --- a/src/components/toast/test/basic/index.ts +++ b/src/components/toast/test/basic/index.ts @@ -61,11 +61,12 @@ class E2EPage { this.nav.present(toast); } - showToastWithCloseButton() { + showToastWithCloseButton(positionString:string) { const toast = Toast.create({ message: 'Your internet connection appears to be offline. Data integrity is not gauranteed.', showCloseButton: true, - closeButtonText: 'Ok' + closeButtonText: 'Ok', + position: positionString }); toast.onDismiss(this.dismissHandler); this.nav.present(toast); diff --git a/src/components/toast/test/basic/main.html b/src/components/toast/test/basic/main.html index 56eee44250..4713777d31 100644 --- a/src/components/toast/test/basic/main.html +++ b/src/components/toast/test/basic/main.html @@ -7,7 +7,9 @@
- + + +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed lacinia purus ac turpis fermentum, nec accumsan nulla rutrum. Aenean lorem est, luctus id iaculis ac, ultricies quis odio. Aenean imperdiet imperdiet ex et vehicula. Suspendisse vulputate turpis quis ultricies porttitor. Proin malesuada tortor at libero laoreet, eu eleifend enim pulvinar. Nulla facilisi. Fusce sit amet mauris mauris. Mauris consequat libero sed egestas tincidunt. diff --git a/src/components/toast/test/toast.spec.ts b/src/components/toast/test/toast.spec.ts index 5b46a70fdb..c14bdbed05 100644 --- a/src/components/toast/test/toast.spec.ts +++ b/src/components/toast/test/toast.spec.ts @@ -11,11 +11,47 @@ describe('Toast', () => { message: 'Please Wait...', showCloseButton: true }); - + + expect(toast.data.position).toEqual('bottom'); expect(toast.data.message).toEqual('Please Wait...'); expect(toast.data.showCloseButton).toEqual(true); }); + it('should create toast with position top', () => { + let toast = Toast.create({ + message: 'Please Wait...', + position: 'top' + }); + + expect(toast.data.position).toEqual('top'); + }); + + it('should create toast with position middle', () => { + let toast = Toast.create({ + message: 'Please Wait...', + position: 'middle' + }); + + expect(toast.data.position).toEqual('middle'); + }); + + it('should create toast with position bottom', () => { + let toast = Toast.create({ + message: 'Please Wait...', + position: 'bottom' + }); + + expect(toast.data.position).toEqual('bottom'); + }); + + it('should set a duration', () => { + let toast = Toast.create({ + message: 'Please Wait...', + duration: 3000 + }); + + expect(toast.data.duration).toEqual(3000); + }); }); }); diff --git a/src/components/toast/toast.ios.scss b/src/components/toast/toast.ios.scss index 61f3a3ca58..67d445f307 100644 --- a/src/components/toast/toast.ios.scss +++ b/src/components/toast/toast.ios.scss @@ -12,22 +12,10 @@ $toast-ios-title-color: #fff !default; $toast-ios-title-font-size: 1.4rem !default; $toast-ios-title-padding: 1.5rem !default; - -ion-toast { - position: absolute; - top: 0; - left: 0; - z-index: $z-index-overlay; - display: block; - - width: $toast-width; - height: $toast-width; -} - .toast-wrapper { position: absolute; right: 10px; - bottom: 10px; + left: 10px; z-index: $z-index-overlay-wrapper; display: block; @@ -40,7 +28,21 @@ ion-toast { background: $toast-ios-background; - transform: translate3d(0, 100%, 0); + &.toast-top { + top: 0; + + transform: translate3d(0, -100%, 0); + } + + &.toast-bottom { + bottom: 0; + + transform: translate3d(0, 100%, 0); + } + + &.toast-middle { + opacity: .01; + } } .toast-message { diff --git a/src/components/toast/toast.md.scss b/src/components/toast/toast.md.scss index e740d17efa..ee2d684cbe 100644 --- a/src/components/toast/toast.md.scss +++ b/src/components/toast/toast.md.scss @@ -12,22 +12,9 @@ $toast-md-title-color: #fff !default; $toast-md-title-font-size: 1.5rem !default; $toast-md-title-padding: 19px 16px 17px !default; - -ion-toast { - position: absolute; - top: 0; - left: 0; - z-index: $z-index-overlay; - display: block; - - width: $toast-width; - height: $toast-width; -} - .toast-wrapper { position: absolute; right: 0; - bottom: 0; left: 0; z-index: $z-index-overlay-wrapper; display: block; @@ -39,7 +26,21 @@ ion-toast { background: $toast-md-background; - transform: translate3d(0, 100%, 0); + &.toast-top { + top: 0; + + transform: translate3d(0, -100%, 0); + } + + &.toast-bottom { + bottom: 0; + + transform: translate3d(0, 100%, 0); + } + + &.toast-middle { + opacity: .01; + } } .toast-message { diff --git a/src/components/toast/toast.scss b/src/components/toast/toast.scss index b7242c6cd5..e72a368518 100644 --- a/src/components/toast/toast.scss +++ b/src/components/toast/toast.scss @@ -39,18 +39,3 @@ ion-toast { .toast-message { flex: 1; } - -.toast-wrapper { - position: absolute; - right: 0; - bottom: 0; - left: 0; - z-index: $z-index-overlay-wrapper; - display: block; - - margin: auto; - - max-width: $toast-max-width; - - transform: translate3d(0, 100%, 0); -} diff --git a/src/components/toast/toast.ts b/src/components/toast/toast.ts index 8391f7047b..6c89b052da 100644 --- a/src/components/toast/toast.ts +++ b/src/components/toast/toast.ts @@ -13,12 +13,11 @@ import {ViewController} from '../nav/view-controller'; /** * @name Toast * @description - * A Toast is a subtle notification that appears at the bottom of the - * screen. It can be used to provide feedback about an operation or to + * A Toast is a subtle notification commonly used in modern applications. + * It can be used to provide feedback about an operation or to * display a system message. The toast appears on top of the app's content, * and can be dismissed by the app to resume user interaction with - * the app. It includes a backdrop, which can optionally be clicked to - * dismiss the toast. + * the app. * * ### Creating * All of the toast options should be passed in the first argument of @@ -27,14 +26,18 @@ import {ViewController} from '../nav/view-controller'; * true in order to display a close button on the toast. See the [create](#create) * method below for all available options. * + * ### Positioning + * Toasts can be positioned at the top, bottom or middle of the + * view port. The position can be passed to the `Toast.create(opts)` method. + * The position option is a string, and the values accepted are `top`, `bottom` and `middle`. + * If the position is not specified, the toast will be displayed at the bottom of the view port. + * * ### Dismissing * The toast can be dismissed automatically after a specific amount of time * by passing the number of milliseconds to display it in the `duration` of - * the toast options. It can also be dismissed by clicking on the backdrop, - * unless `enableBackdropDismiss` is set to `false` upon creation. If `showCloseButton` - * is set to true, then the close button will dismiss the toast. To dismiss - * the toast after creation, call the `dismiss()` method on the Toast instance. - * The `onDismiss` function can be called to perform an action after the toast + * the toast options. If `showCloseButton` is set to true, then the close button + * will dismiss the toast. To dismiss the toast after creation, call the `dismiss()` + * method on the Toast instance. The `onDismiss` function can be called to perform an action after the toast * is dismissed. * * @usage @@ -46,7 +49,8 @@ import {ViewController} from '../nav/view-controller'; * presentToast() { * let toast = Toast.create({ * message: 'User was added successfully', - * duration: 3000 + * duration: 3000, + * position: 'top' * }); * * toast.onDismiss(() => { @@ -63,8 +67,11 @@ export class Toast extends ViewController { constructor(opts: ToastOptions = {}) { opts.dismissOnPageChange = isPresent(opts.dismissOnPageChange) ? !!opts.dismissOnPageChange : false; - super(ToastCmp, opts); + // set the position to the bottom if not provided + if ( ! opts.position || ! this.isVaidPosition(opts.position)) { + opts.position = TOAST_POSITION_BOTTOM; + } this.viewType = 'toast'; this.isOverlay = true; this.usePortal = true; @@ -76,7 +83,6 @@ export class Toast extends ViewController { } - /** * @private */ @@ -85,6 +91,13 @@ export class Toast extends ViewController { return this._nav && this._nav.config.get(key); } + /** + * @private + */ + isVaidPosition(position: string) { + return position === TOAST_POSITION_TOP || position === TOAST_POSITION_MIDDLE || position === TOAST_POSITION_BOTTOM; + } + /** * @param {string} message Toast message content */ @@ -100,6 +113,7 @@ export class Toast extends ViewController { * |-----------------------|-----------|-----------------|---------------------------------------------------------------------------------------------------------------| * | message | `string` | - | The message for the toast. Long strings will wrap and the toast container will expand. | * | duration | `number` | - | How many milliseconds to wait before hiding the toast. By default, it will show until `dismiss()` is called. | + * | position | `string` | "bottom" | The position of the toast on the screen. "top", "middle", and "bottom" are the accepted values. | * | cssClass | `string` | - | Any additional class for custom styles. | * | showCloseButton | `boolean` | false | Whether or not to show a button to close the toast. | * | closeButtonText | `string` | "Close" | Text to display in the close button. | @@ -110,9 +124,12 @@ export class Toast extends ViewController { static create(opts: ToastOptions = {}) { return new Toast(opts); } - } +/* Don't expose these for now - let's move to an enum or something long term */ +const TOAST_POSITION_TOP: string = 'top'; +const TOAST_POSITION_MIDDLE: string = 'middle'; +const TOAST_POSITION_BOTTOM: string = 'bottom'; /** * @private @@ -120,7 +137,11 @@ export class Toast extends ViewController { @Component({ selector: 'ion-toast', template: ` -

+
{{d.message}}