Skip to content

Commit

Permalink
feat(module:toast): support position top and bottom (#450)
Browse files Browse the repository at this point in the history
  • Loading branch information
nuonuoge authored and fisherspy committed May 21, 2019
1 parent a14ea6b commit 77c326a
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 31 deletions.
12 changes: 12 additions & 0 deletions components/toast/demo/basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import { ToastService } from 'ng-zorro-antd-mobile';
<WhiteSpace></WhiteSpace>
<div Button (onClick)="showToastNoMask()">without mask</div>
<WhiteSpace></WhiteSpace>
<div Button (onClick)="showToastTop()">position top</div>
<WhiteSpace></WhiteSpace>
<div Button (onClick)="showToastBottom()">position bottom</div>
<WhiteSpace></WhiteSpace>
<div Button (onClick)="showCustomIcon(content)">custom content</div>
<WhiteSpace></WhiteSpace>
<div Button (onClick)="successToast()">success</div>
Expand Down Expand Up @@ -39,6 +43,14 @@ export class DemoToastBasicComponent {
const toast = ToastService.info('Toast without mask !!!', 4000, null, false);
}

showToastTop() {
const toast = ToastService.info('Toast position top', 4000, null, false, 'top');
}

showToastBottom() {
const toast = ToastService.info('Toast position top', 4000, null, false, 'bottom');
}

showCustomIcon(event) {
const toast = ToastService.info(event);
}
Expand Down
1 change: 1 addition & 0 deletions components/toast/doc/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Properties | Descrition | Type | Default
| duration | Delay time to close, which units is millisecond | number | 3000 |
| onClose | A callback function Triggered when the Toast is closed | Function | - |
| mask | Whether to show a transparent mask, which will prevent touch event of the whole page | Boolean | true |
| position | enum{'top', 'middle', 'bottom'} | string | 'middle' |

> **Notice:** OnClose is invalid and Toast does not hide, If set duration = 0, toast will not auto hide, you have to manually do it.
Expand Down
1 change: 1 addition & 0 deletions components/toast/doc/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ subtitle: 轻提示
| duration | 自动关闭的延时,单位毫秒 | number | 3000 |
| onClose | 关闭后回调 | Function ||
| mask | 是否显示透明蒙层,防止触摸穿透 | Boolean | true |
| position | enum{'top', 'middle', 'bottom'} | string | 'middle' |

> **注:** duration = 0 时,onClose 无效,toast 不会消失;隐藏 toast 需要手动调用 hide
Expand Down
38 changes: 37 additions & 1 deletion components/toast/style/addon.less
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
@import '../../style/themes/default';

@toastPrefixCls: am-toast;

.@{toastPrefixCls} {
display: block;
}
&&-mask {
&&&-top {
align-items: flex-start;
padding-top: @v-spacing-md;
}
&&&-middle {
align-items: center;
}
&&&-bottom {
align-items: flex-end;
padding-bottom: @v-spacing-md;
}
}

&&-nomask {
&&&-top {
top: 0%;
.@{toastPrefixCls}-notice {
transform: translateX(-50%) translateY(calc(0% + @v-spacing-md));
}
}
&&&-middle {
top: 50%;
.@{toastPrefixCls}-notice {
transform: translateX(-50%) translateY(-50%);
}
}
&&&-bottom {
top: 100%;
.@{toastPrefixCls}-notice {
transform: translateX(-50%) translateY(calc(-100% - @v-spacing-md));
}
}
}
}
1 change: 1 addition & 0 deletions components/toast/toast-options.provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export class ToastOptions {
content: any;
mask: boolean;
iconType: string;
position: string;
}
25 changes: 23 additions & 2 deletions components/toast/toast.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,26 @@ describe('ToastComponent', () => {
expect(toastEle.nativeElement.classList).toContain('am-toast-nomask', 'mask is false');
});

it('position should work', () => {
expect(toastEle.nativeElement.classList).toContain('am-toast-mask-middle');
component.position = 'top';
fixture.detectChanges();
expect(toastEle.nativeElement.classList).toContain('am-toast-mask-top');
component.position = 'bottom';
fixture.detectChanges();
expect(toastEle.nativeElement.classList).toContain('am-toast-mask-bottom');
component.mask = false;
component.position = 'top';
fixture.detectChanges();
expect(toastEle.nativeElement.classList).toContain('am-toast-nomask-top');
component.position = 'middle';
fixture.detectChanges();
expect(toastEle.nativeElement.classList).toContain('am-toast-nomask-middle');
component.position = 'bottom';
fixture.detectChanges();
expect(toastEle.nativeElement.classList).toContain('am-toast-nomask-bottom');
});

it('should showToast work', () => {
const button = buttons[0].nativeElement;
button.click();
Expand Down Expand Up @@ -133,7 +153,7 @@ describe('ToastComponent', () => {
@Component({
selector: 'test-toast',
template: `
<Toast [content]="content" [iconType]="iconType" [mask]="mask"></Toast>
<Toast [content]="content" [iconType]="iconType" [mask]="mask" [position]="position"></Toast>
<div Button (onClick)="showToast()">text only</div>
<div Button (onClick)="showToastNoMask()">without mask</div>
<div Button (onClick)="showCustomIcon(content1)">custom content</div>
Expand All @@ -156,14 +176,15 @@ export class TestToastComponent {
content: any = '123';
iconType = '';
mask = true;
position = 'middle';

@ViewChild('contentTpl')
contentTpl: ViewChild;

constructor(private _toast: ToastService) {}

showToast() {
const toast = ToastService.show('This is a toast tips !!!', 0);
const toast = ToastService.show('This is a toast tips !!!', 0, true, this.position);
setTimeout(() => {
ToastService.hide();
}, 3000);
Expand Down
28 changes: 15 additions & 13 deletions components/toast/toast.component.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import { Component, ViewEncapsulation, Input, TemplateRef, HostBinding, NgZone } from '@angular/core';
import { Component, ViewEncapsulation, Input, TemplateRef, NgZone } from '@angular/core';

@Component({
selector: 'Toast',
encapsulation: ViewEncapsulation.None,
templateUrl: './toast.component.html'
templateUrl: './toast.component.html',
host: {
'[class.am-toast]': 'true',
'[class.am-toast-mask]': 'mask',
'[class.am-toast-mask-top]': `mask && position === 'top'`,
'[class.am-toast-mask-middle]': `mask && position === 'middle'`,
'[class.am-toast-mask-bottom]': `mask && position === 'bottom'`,
'[class.am-toast-nomask]': '!mask',
'[class.am-toast-nomask-top]': `!mask && position === 'top'`,
'[class.am-toast-nomask-middle]': `!mask && position === 'middle'`,
'[class.am-toast-nomask-bottom]': `!mask && position === 'bottom'`,
}
})
export class ToastComponent {
prefixCls: string = 'am-toast';
Expand Down Expand Up @@ -39,17 +50,8 @@ export class ToastComponent {
this._iconType = value;
});
}

@HostBinding('class.am-toast')
amToast: boolean = true;
@HostBinding('class.am-toast-mask')
get amToastMask(): boolean {
return this.mask;
}
@HostBinding('class.am-toast-nomask')
get amToastNoMask(): boolean {
return !this.mask;
}
@Input()
position: string = 'middle';

constructor(private _zone: NgZone) {}
}
30 changes: 16 additions & 14 deletions components/toast/toast.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export class ToastService {

static _initConfig(config: Object, options: ToastOptions): Object {
const props = {};
const optionalParams: string[] = ['content', 'iconType', 'mask'];
const optionalParams: string[] = ['content', 'iconType', 'mask', 'position'];

config = Object.assign(options, config);
optionalParams.forEach(key => {
Expand All @@ -53,17 +53,19 @@ export class ToastService {

props['iconType'] = iconType;
props['mask'] = options.mask;
props['position'] = options.position;
return props;
}

static notice(config: ConfigInterface, type, timeInterval = 2000, onClose, mask = true) {
static notice(config: ConfigInterface, type, timeInterval = 2000, onClose, mask = true, position = 'middle') {
// 如果已经存在,在没有遮罩层的情况下,会响应别的toast,需要清除原来的
if (ToastService.compRef) {
ToastService.hide();
}
const options: ToastOptions = new ToastOptions();
options.iconType = type;
options.mask = mask;
options.position = position;
const props = ToastService._initConfig(config, options);

document.body.insertBefore(document.createElement(ToastService._toastCompFactory.selector), document.body.firstChild);
Expand All @@ -90,55 +92,55 @@ export class ToastService {
/**
* Open info dialog
*/
static info(content?: string, timeInterval?: number, onClose?: () => void, mask?: boolean) {
static info(content?: string, timeInterval?: number, onClose?: () => void, mask?: boolean, position?: string) {
const config = Object.assign({
iconType: 'info',
content: content
});
return ToastService.notice(config, 'info', timeInterval, onClose, mask);
return ToastService.notice(config, 'info', timeInterval, onClose, mask, position);
}

/**
* Open success dialog
*/
static success(content?: string, timeInterval?: number, onClose?: () => void, mask?: boolean) {
static success(content?: string, timeInterval?: number, onClose?: () => void, mask?: boolean, position?: string) {
const config = Object.assign({
iconType: 'success',
content: content
});
return ToastService.notice(config, 'success', timeInterval, onClose, mask);
return ToastService.notice(config, 'success', timeInterval, onClose, mask, position);
}

static show(content?: string, timeInterval?: number, mask?: boolean) {
static show(content?: string, timeInterval?: number, mask?: boolean, position?: string) {
const config = Object.assign({
iconType: 'info',
content: content
});
return ToastService.notice(config, 'info', timeInterval, () => {}, mask);
return ToastService.notice(config, 'info', timeInterval, () => {}, mask, position);
}

static fail(content?: string, timeInterval?: number, onClose?: () => void, mask?: boolean) {
static fail(content?: string, timeInterval?: number, onClose?: () => void, mask?: boolean, position?: string) {
const config = Object.assign({
iconType: 'fail',
content: content
});
return ToastService.notice(config, 'fail', timeInterval, onClose, mask);
return ToastService.notice(config, 'fail', timeInterval, onClose, mask, position);
}

static offline(content?: string, timeInterval?: number, onClose?: () => void, mask?: boolean) {
static offline(content?: string, timeInterval?: number, onClose?: () => void, mask?: boolean, position?: string) {
const config = Object.assign({
iconType: 'offline',
content: content
});
return ToastService.notice(config, 'offline', timeInterval, onClose, mask);
return ToastService.notice(config, 'offline', timeInterval, onClose, mask, position);
}

static loading(content?: string, timeInterval?: number, onClose?: () => void, mask?: boolean) {
static loading(content?: string, timeInterval?: number, onClose?: () => void, mask?: boolean, position?: string) {
const config = Object.assign({
iconType: 'loading',
content: content
});
return ToastService.notice(config, 'loading', timeInterval, onClose, mask);
return ToastService.notice(config, 'loading', timeInterval, onClose, mask, position);
}

static hide() {
Expand Down
2 changes: 1 addition & 1 deletion tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@
"no-output-on-prefix": false,
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"use-host-property-decorator": false,
"no-input-rename": false,
"no-output-rename": true,
"use-life-cycle-interface": true,
Expand Down

0 comments on commit 77c326a

Please sign in to comment.