Skip to content

Commit

Permalink
feat(module:drawer): support top and bottom placement (#2039)
Browse files Browse the repository at this point in the history
close #2015
  • Loading branch information
hsuanxyz authored and Jason committed Sep 7, 2018
1 parent 64d191c commit 693b4eb
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 61 deletions.
6 changes: 5 additions & 1 deletion components/core/util/convert.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
import { coerceBooleanProperty, coerceCssPixelValue, coerceNumberProperty } from '@angular/cdk/coercion';
import { FunctionProp } from '../types/common-wrap';

export function toBoolean(value: boolean | string): boolean {
Expand All @@ -9,6 +9,10 @@ export function toNumber<D>(value: number | string, fallback: D): number | D {
return coerceNumberProperty(value, fallback);
}

export function toCssPixel(value: number | string): string {
return coerceCssPixelValue(value);
}

// Get the funciton-property type's value
export function valueFunctionProp<T>(prop: FunctionProp<T>, ...args: any[]): T { // tslint:disable-line: no-any
return typeof prop === 'function' ? prop(...args) : prop;
Expand Down
15 changes: 0 additions & 15 deletions components/drawer/demo/basic-left.md

This file was deleted.

26 changes: 0 additions & 26 deletions components/drawer/demo/basic-left.ts

This file was deleted.

15 changes: 15 additions & 0 deletions components/drawer/demo/placement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
order: 1
title:
zh-CN: 自定义位置
en-US: Custom Placement
---

## zh-CN

自定义位置,点击触发按钮抽屉从相应的位置滑出,点击遮罩区关闭

## en-US

Basic drawer.

32 changes: 32 additions & 0 deletions components/drawer/demo/placement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Component } from '@angular/core';

@Component({
selector: 'nz-demo-drawer-placement',
template: `
<nz-radio-group [(ngModel)]="placement">
<label nz-radio nzValue="top">top</label>
<label nz-radio nzValue="right">right</label>
<label nz-radio nzValue="bottom">bottom</label>
<label nz-radio nzValue="left">left</label>
</nz-radio-group>
<button nz-button nzType="primary" (click)="open()">Open</button>
<nz-drawer [nzClosable]="false" [nzVisible]="visible" [nzPlacement]="placement" nzTitle="Basic Drawer" (nzOnClose)="close()">
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</nz-drawer>
`
})

export class NzDemoDrawerPlacementComponent {

visible = false;
placement = 'left';
open(): void {
this.visible = true;
}

close(): void {
this.visible = false;
}
}
8 changes: 5 additions & 3 deletions components/drawer/doc/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ A Drawer is a panel that is typically overlaid on top of a page and slides in fr
| `[nzBodyStyle]` | Body style for modal body element. Such as height, padding etc. | `object` | `{}` |
| `[nzTitle]` | The title for Drawer. | `string` `TemplateRef<{}>` | - |
| `[nzVisible]` | Whether the Drawer dialog is visible or not. | `boolean` | `false` |
| `[nzWidth]` | Width of the Drawer dialog. | `number` `string` | `256` |
| `[nzPlacement]` | The placement of the Drawer. | `'top'` `'right'` `'bottom'` `'left'` | `'right'` |
| `[nzWidth]` | Width of the Drawer dialog, only when placement is `'right'` or `'left'`. | `number` `string` | `256` |
| `[nzHeight]` | Height of the Drawer dialog, only when placement is `'top'` or `'bottom'`. | `number` `string` | `256` |
| `[nzOffsetX]` | The the X coordinate offset(px), only when placement is `'right'` or `'left'`. | `number` | `0` |
| `[nzOffsetY]` | The the Y coordinate offset(px), only when placement is `'top'` or `'bottom'`. | `number` | `0` |
| `[nzWrapClassName]` | The class name of the container of the Drawer dialog. | `string` | - |
| `[nzZIndex]` | The `z-index` of the Drawer. | `number` | `1000` |
| `[nzPlacement]` | The placement of the Drawer. | `'left'` `'right'` | `'right'` |
| `[nzOffsetX]` | The the X coordinate offset(px) | `number` | `0` |
| `(nzOnClose)` | Specify a callback that will be called when a user clicks mask, close button or Cancel button. | `EventEmitter<MouseEvent>` | - |
8 changes: 5 additions & 3 deletions components/drawer/doc/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ title: Drawer
| `[nzBodyStyle]` | Modal body 样式 | `object` | `{}` |
| `[nzTitle]` | 标题 | `string` `TemplateRef<{}>` | - |
| `[nzVisible]` | Drawer 是否可见 | `boolean` | - |
| `[nzWidth]` | 宽度 | `number` `string` | `256` |
| `[nzPlacement]` | 抽屉的方向 | `'top'` `'right'` `'bottom'` `'left'` | `'right'` |
| `[nzWidth]` | 宽度, 只在方向为 `'right'``'left'` 时生效 | `number` `string` | `256` |
| `[nzHeight]` | 高度, 只在方向为 `'top'``'bottom'` 时生效 | `number` `string` | `256` |
| `[nzOffsetX]` | x 坐标移量(px), 只在方向为 `'right'``'left'` 时生效 | `number` | `0` |
| `[nzOffsetY]` | y 坐标移量(px), 高度, 只在方向为 `'top'``'bottom'` 时生效 | `number` | `0` |
| `[nzWrapClassName]` | 对话框外层容器的类名 | `string` | - |
| `[nzZIndex]` | 设置 Drawer 的 `z-index` | `number` | `1000` |
| `[nzPlacement]` | 抽屉的方向 | `'left'` `'right'` | `'right'` |
| `[nzOffsetX]` | x 坐标移量(px) | `number` | `0` |
| `(nzOnClose)` | 点击遮罩层或右上角叉或取消按钮的回调 | `EventEmitter<MouseEvent>` | - |
8 changes: 6 additions & 2 deletions components/drawer/nz-drawer.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@
<div
class="ant-drawer"
[class.ant-drawer-open]="isOpen"
[class.ant-drawer-top]="nzPlacement === 'top'"
[class.ant-drawer-bottom]="nzPlacement === 'bottom'"
[class.ant-drawer-right]="nzPlacement === 'right'"
[class.ant-drawer-left]="nzPlacement === 'left'">
<div class="ant-drawer-mask" (click)="maskClick($event)" *ngIf="nzMask" [style.zIndex]="nzZIndex" [ngStyle]="nzMaskStyle"></div>
<div class="ant-drawer-content-wrapper {{ nzWrapClassName }}"
[style.zIndex]="nzZIndex"
[style.transform]="transform">
[style.width]="width"
[style.height]="height"
[style.transform]="transform">
<div class="ant-drawer-content">
<div style="overflow: auto; height: 100%;" [style.width]="width">
<div class="ant-drawer-wrapper-body">
<div *ngIf="nzTitle" class="ant-drawer-header">
<div class="ant-drawer-title">
<ng-container [ngSwitch]="true">
Expand Down
34 changes: 27 additions & 7 deletions components/drawer/nz-drawer.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import { CdkOverlayOrigin, Overlay, OverlayConfig, OverlayRef } from '@angular/c
import { TemplatePortal } from '@angular/cdk/portal';
import { NzScrollStrategyOptions } from '../core/overlay/scroll/nz-scroll-strategy-options';

import { InputBoolean } from '../core/util/convert';
import { toCssPixel, InputBoolean } from '../core/util/convert';

export type NzDrawerPlacement = 'top' | 'right' | 'bottom' | 'left';

@Component({
selector : 'nz-drawer',
Expand All @@ -31,15 +33,31 @@ export class NzDrawerComponent implements OnInit, OnDestroy {
isOpen = false;

get transform(): string {
if (this.nzPlacement === 'left') {
return this.isOpen ? `translateX(${this.nzOffsetX}px)` : `translateX(-${this.width})`;
} else {
return this.isOpen ? `translateX(-${this.nzOffsetX}px)` : `translateX(${this.width})`;

switch (this.nzPlacement) {
case 'left':
return this.isOpen ? `translateX(${this.nzOffsetX}px)` : `translateX(-${this.width})`;
case 'right':
return this.isOpen ? `translateX(-${this.nzOffsetX}px)` : `translateX(${this.width})`;
case 'top':
return this.isOpen ? `translateY(${this.nzOffsetY}px)` : `translateY(-${this.height})`;
case 'bottom':
return this.isOpen ? `translateY(-${this.nzOffsetY}px)` : `translateY(${this.height})`;
default:
return '';
}
}

get width(): string {
return typeof this.nzWidth === 'number' ? `${this.nzWidth}px` : this.nzWidth;
return this.isLeftOrRight ? toCssPixel(this.nzWidth) : null;
}

get height(): string {
return !this.isLeftOrRight ? toCssPixel(this.nzHeight) : null;
}

get isLeftOrRight(): boolean {
return this.nzPlacement === 'left' || this.nzPlacement === 'right';
}

@ViewChild('drawerTemplate') drawerTemplate: TemplateRef<{}>;
Expand All @@ -51,9 +69,11 @@ export class NzDrawerComponent implements OnInit, OnDestroy {
@Input() nzBodyStyle: object = {};
@Input() nzWrapClassName: string;
@Input() nzWidth: number | string = 256;
@Input() nzPlacement: 'left' | 'right' = 'right';
@Input() nzHeight: number | string = 256;
@Input() nzPlacement: NzDrawerPlacement = 'right';
@Input() nzZIndex = 1000;
@Input() nzOffsetX = 0;
@Input() nzOffsetY = 0;
@Output() nzOnClose = new EventEmitter<MouseEvent>();

@Input()
Expand Down
85 changes: 81 additions & 4 deletions components/drawer/nz-drawer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,19 +151,41 @@ describe('NzDrawerComponent', () => {
});

it('should support custom width', () => {
component.width = '300px';
component.width = '500px';
component.open();
fixture.detectChanges();
expect(overlayContainerElement.querySelector('.ant-drawer').classList.contains('ant-drawer-open')).toBe(true);
expect((overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content > div') as HTMLElement).getBoundingClientRect().width).toBe(300);
expect((overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content') as HTMLElement).getBoundingClientRect().width).toBe(500);
});

it('should support custom number type width', () => {
component.width = 500;
component.width = 520;
component.open();
fixture.detectChanges();
expect(overlayContainerElement.querySelector('.ant-drawer').classList.contains('ant-drawer-open')).toBe(true);
expect((overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content > div') as HTMLElement).getBoundingClientRect().width).toBe(500);
expect((overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content') as HTMLElement).getBoundingClientRect().width).toBe(520);
});

it('should support custom height', () => {
component.height = '500px';
component.placement = 'top';
component.open();
fixture.detectChanges();
expect(overlayContainerElement.querySelector('.ant-drawer').classList.contains('ant-drawer-open')).toBe(true);
expect((overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content-wrapper') as HTMLElement).getBoundingClientRect().height).toBe(500);
component.placement = 'left';
fixture.detectChanges();
});

it('should support custom number type height', () => {
component.height = 520;
component.placement = 'top';
component.open();
fixture.detectChanges();
expect(overlayContainerElement.querySelector('.ant-drawer').classList.contains('ant-drawer-open')).toBe(true);
expect((overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content-wrapper') as HTMLElement).getBoundingClientRect().height).toBe(520);
component.placement = 'left';
fixture.detectChanges();
});

it('should nzWrapClassName work', () => {
Expand All @@ -186,10 +208,44 @@ describe('NzDrawerComponent', () => {
fixture.detectChanges();
expect(overlayContainerElement.querySelector('.ant-drawer').classList.contains('ant-drawer-open')).toBe(true);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-left')).toBe(true);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-bottom')).toBe(false);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-top')).toBe(false);
component.placement = 'right';
fixture.detectChanges();
component.close();
fixture.detectChanges();
component.open();
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-left')).toBe(false);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-right')).toBe(true);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-bottom')).toBe(false);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-top')).toBe(false);
component.placement = 'top';
fixture.detectChanges();
component.close();
fixture.detectChanges();
component.open();
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-left')).toBe(false);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-right')).toBe(false);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-bottom')).toBe(false);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-top')).toBe(true);
component.placement = 'bottom';
fixture.detectChanges();
component.close();
fixture.detectChanges();
component.open();
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-left')).toBe(false);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-right')).toBe(false);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-bottom')).toBe(true);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-top')).toBe(false);
component.close();
fixture.detectChanges();
component.placement = 'Invalid';
fixture.detectChanges();
component.open();
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-left')).toBe(false);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-right')).toBe(false);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-bottom')).toBe(false);
expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-top')).toBe(false);
component.close();
fixture.detectChanges();
});
Expand All @@ -211,6 +267,23 @@ describe('NzDrawerComponent', () => {
fixture.detectChanges();
});

it('should nzOffsetY work', () => {
component.open();
component.placement = 'top';
component.height = '300px';
component.offsetY = 100;
fixture.detectChanges();
expect(overlayContainerElement.querySelector('.ant-drawer').classList.contains('ant-drawer-open')).toBe(true);
expect((overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content-wrapper') as HTMLElement).style.transform).toBe('translateY(100px)');
fixture.detectChanges();
component.placement = 'bottom';
component.offsetY = 100;
fixture.detectChanges();
expect((overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content-wrapper') as HTMLElement).style.transform).toBe('translateY(-100px)');
component.close();
fixture.detectChanges();
});

});

@Component({
Expand All @@ -228,9 +301,11 @@ describe('NzDrawerComponent', () => {
[nzMask]="showMask"
[nzVisible]="visible"
[nzWidth]="width"
[nzHeight]="height"
[nzPlacement]="placement"
[nzTitle]="title"
[nzOffsetX]="offsetX"
[nzOffsetY]="offsetY"
(nzOnClose)="close()">
<p>Some contents...</p>
<p>Some contents...</p>
Expand All @@ -247,8 +322,10 @@ class NzTestDrawerComponent {
title = null;
stringTitle = 'test';
width: string | number = '300px';
height: string | number = '300px';
placement = 'left';
offsetX = 0;
offsetY = 0;
@ViewChild('customTitle') templateTitle: TemplateRef<void>;

@ViewChild(NzDrawerComponent) drawerComponent: NzDrawerComponent;
Expand Down

0 comments on commit 693b4eb

Please sign in to comment.