diff --git a/components/core/util/convert.ts b/components/core/util/convert.ts index 50831eff9dd..612768571a9 100644 --- a/components/core/util/convert.ts +++ b/components/core/util/convert.ts @@ -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 { @@ -9,6 +9,10 @@ export function toNumber(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(prop: FunctionProp, ...args: any[]): T { // tslint:disable-line: no-any return typeof prop === 'function' ? prop(...args) : prop; diff --git a/components/drawer/demo/basic-left.md b/components/drawer/demo/basic-left.md deleted file mode 100755 index 675c6cd440e..00000000000 --- a/components/drawer/demo/basic-left.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -order: 1 -title: - zh-CN: 左侧滑出 - en-US: Left Slider ---- - -## zh-CN - -基础抽屉,点击触发按钮抽屉从左滑出,点击遮罩区关闭 - -## en-US - -Basic drawer. - diff --git a/components/drawer/demo/basic-left.ts b/components/drawer/demo/basic-left.ts deleted file mode 100755 index e406b5fb843..00000000000 --- a/components/drawer/demo/basic-left.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'nz-demo-drawer-basic-left', - template: ` - - -

Some contents...

-

Some contents...

-

Some contents...

-
- ` -}) - -export class NzDemoDrawerBasicLeftComponent { - - visible = false; - - open(): void { - this.visible = true; - } - - close(): void { - this.visible = false; - } -} diff --git a/components/drawer/demo/placement.md b/components/drawer/demo/placement.md new file mode 100755 index 00000000000..e3f15c97ab2 --- /dev/null +++ b/components/drawer/demo/placement.md @@ -0,0 +1,15 @@ +--- +order: 1 +title: + zh-CN: 自定义位置 + en-US: Custom Placement +--- + +## zh-CN + +自定义位置,点击触发按钮抽屉从相应的位置滑出,点击遮罩区关闭 + +## en-US + +Basic drawer. + diff --git a/components/drawer/demo/placement.ts b/components/drawer/demo/placement.ts new file mode 100755 index 00000000000..e096385d256 --- /dev/null +++ b/components/drawer/demo/placement.ts @@ -0,0 +1,32 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'nz-demo-drawer-placement', + template: ` + + + + + + + + +

Some contents...

+

Some contents...

+

Some contents...

+
+ ` +}) + +export class NzDemoDrawerPlacementComponent { + + visible = false; + placement = 'left'; + open(): void { + this.visible = true; + } + + close(): void { + this.visible = false; + } +} diff --git a/components/drawer/doc/index.en-US.md b/components/drawer/doc/index.en-US.md index 3be9d09e657..394854877d2 100755 --- a/components/drawer/doc/index.en-US.md +++ b/components/drawer/doc/index.en-US.md @@ -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` | - | diff --git a/components/drawer/doc/index.zh-CN.md b/components/drawer/doc/index.zh-CN.md index 973a4b25e62..e2a94f98970 100755 --- a/components/drawer/doc/index.zh-CN.md +++ b/components/drawer/doc/index.zh-CN.md @@ -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` | - | diff --git a/components/drawer/nz-drawer.component.html b/components/drawer/nz-drawer.component.html index a5ade681791..693e5f82b92 100644 --- a/components/drawer/nz-drawer.component.html +++ b/components/drawer/nz-drawer.component.html @@ -2,14 +2,18 @@
+ [style.width]="width" + [style.height]="height" + [style.transform]="transform">
-
+
diff --git a/components/drawer/nz-drawer.component.ts b/components/drawer/nz-drawer.component.ts index b5f671b345b..96409e41f8e 100644 --- a/components/drawer/nz-drawer.component.ts +++ b/components/drawer/nz-drawer.component.ts @@ -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', @@ -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<{}>; @@ -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(); @Input() diff --git a/components/drawer/nz-drawer.spec.ts b/components/drawer/nz-drawer.spec.ts index 6fbd2030dbf..60aae834a18 100644 --- a/components/drawer/nz-drawer.spec.ts +++ b/components/drawer/nz-drawer.spec.ts @@ -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', () => { @@ -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(); }); @@ -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({ @@ -228,9 +301,11 @@ describe('NzDrawerComponent', () => { [nzMask]="showMask" [nzVisible]="visible" [nzWidth]="width" + [nzHeight]="height" [nzPlacement]="placement" [nzTitle]="title" [nzOffsetX]="offsetX" + [nzOffsetY]="offsetY" (nzOnClose)="close()">

Some contents...

Some contents...

@@ -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; @ViewChild(NzDrawerComponent) drawerComponent: NzDrawerComponent;