diff --git a/components/drawer/demo/basic.md b/components/drawer/demo/basic.md
new file mode 100644
index 0000000000..0d7f56886b
--- /dev/null
+++ b/components/drawer/demo/basic.md
@@ -0,0 +1,53 @@
+---
+order: 0
+title:
+ zh-CN: 基本
+ en-US: Basic
+---
+
+## zh-CN
+
+第一个对话框。
+
+## en-US
+
+Basic modal.
+
+```jsx
+import { Drawer, Button } from 'antd';
+
+class App extends React.Component {
+ state = { visible: false };
+ showDrawer = () => {
+ this.setState({
+ visible: true,
+ });
+ };
+ onClose = () => {
+ this.setState({
+ visible: false,
+ });
+ };
+ render() {
+ return (
+
+
+
+ Some contents...
+ Some contents...
+ Some contents...
+
+
+ );
+ }
+}
+
+ReactDOM.render(, mountNode);
+```
diff --git a/components/drawer/index.en-US.md b/components/drawer/index.en-US.md
new file mode 100644
index 0000000000..4802e32a7d
--- /dev/null
+++ b/components/drawer/index.en-US.md
@@ -0,0 +1,32 @@
+---
+type: Feedback
+category: Components
+subtitle: Drawer
+title: Drawer
+---
+
+Drawer container
+
+## When To Use
+
+
+## API
+
+| 参数 | 说明 | 类型 | 默认值 |
+| --- | --- | --- | --- |
+| closable | Whether a close (x) button is visible on top right of the Drawer dialog or not | boolean | true |
+| destroyOnClose | Whether to unmount child compenents on onClose | boolean | false |
+| getContainer | Return the mount node for Drawer | (instance): HTMLElement | () => document.body |
+| mask | Whether show mask or not. | Boolean | true |
+| maskClosable | Whether to close the Drawer dialog when the mask (area outside the Drawer) is clicked | boolean | true |
+| maskStyle | Style for Drawer's mask element. | object | {} |
+| style | Style of floating layer, typically used at least for adjusting the position. | object | - |
+| title | The Drawer dialog's title | string\|ReactNode | - |
+| visible | Whether the Drawer dialog is visible or not | boolean | false |
+| width | Width of the Drawer dialog | string\|number | 520 |
+| wrapClassName | The class name of the container of the Drawer dialog | string | - |
+| zIndex | The `z-index` of the Drawer | Number | 1000 |
+| placement | The direction of the Drawer | 'left' | 'right' | 'left'
+| onClose | Specify a function that will be called when a user clicks mask, close button on top right or Cancel button | function(e) | - |
+
+
diff --git a/components/drawer/index.md b/components/drawer/index.md
deleted file mode 100644
index 48253e0ea6..0000000000
--- a/components/drawer/index.md
+++ /dev/null
@@ -1,28 +0,0 @@
-
----
-category: Components
-type: Other
-title: Drawer
-subtitle: 抽屉
----
-
-## API
-| 参数 | 说明 | 类型 | 默认值 |
-| --- | --- | --- | --- |
-| className | 抽屉的类属性 | string | `drawer` |
-| openClassName | 打开抽屉时的类属性 | string | `drawer-open`|
-| bodyStyle | Drawer 面板 样式 | object | {} |
-| mask | 是否展示遮罩 | Boolean | true |
-| maskClosable | 点击蒙层是否允许关闭 | boolean | true |
-| maskStyle | 遮罩样式 | object | {} |
-| showIcon | 是否显示抽屉的 icon | boolean | true |
-| icon | 抽屉的 icon | ReactNode | node |
-| visible | 抽屉是否可见 | boolean | false |
-| getContainer | 指定 抽屉挂载节点 | (instance)=> HTMLElement | `body` |
-| width | 抽屉的宽度 | string | `60vw` |
-| placement | 抽屉的方向 | `left` 或 `right` | `left` |
-| onChange | 面板状态改变事件 | (state:boolean)=>void | null |
-| onIconClick | icon 点击事件 | (e:event)=>void | null
-| destroyOnClose | 关闭时销毁 Drawer 里的子元素 | boolean | false |
-
-
diff --git a/components/drawer/index.tsx b/components/drawer/index.tsx
new file mode 100644
index 0000000000..1ea063fa16
--- /dev/null
+++ b/components/drawer/index.tsx
@@ -0,0 +1,120 @@
+import * as React from 'react';
+import RcDrawer from 'rc-drawer-menu';
+import { isNull } from 'util';
+
+type EventType =
+ | React.MouseEvent
+ | React.MouseEvent;
+
+export interface IDrawerProps {
+ closable?: boolean;
+ // @todo 下一步增加
+ destroyOnClose?: boolean;
+ getContainer?: HTMLElement;
+ maskClosable?: boolean;
+ mask?: boolean;
+ maskStyle?: React.CSSProperties;
+ style?: React.CSSProperties;
+ title?: React.ReactNode;
+ visible?: boolean;
+ width?: number | string;
+ wrapClassName?: string;
+ // @todo 下一步增加
+ zIndex?: number;
+ prefixCls?: string;
+ placement?: 'left' | 'right' ;
+ onClose?: (e: EventType) => void;
+}
+
+export interface IDrawerState {
+ visible?: boolean;
+}
+
+export default class Drawer extends React.Component<
+ IDrawerProps,
+ IDrawerState
+> {
+ static defaultProps = {
+ prefixCls: 'ant-drawer',
+ width: 325,
+ closable: true,
+ };
+ static getDerivedStateFromProps(
+ nextProps: IDrawerProps,
+ prevState: IDrawerState,
+ ) {
+ const nextState: IDrawerState = {};
+ if (!isNull(nextProps.visible) && nextProps.visible !== prevState.visible) {
+ nextState.visible = nextProps.visible;
+ }
+ return nextState;
+ }
+ constructor(props: IDrawerProps) {
+ super(props);
+ this.state = {
+ visible: false,
+ };
+ }
+ close = (e: EventType) => {
+ if (!isNull(this.props.visible)) {
+ if (this.props.onClose) {
+ this.props.onClose(e);
+ }
+ return;
+ }
+ this.setState({
+ visible: false,
+ });
+ }
+ onMaskClick = (e: EventType) => {
+ if (!this.props.maskClosable) {
+ return;
+ }
+ this.close(e);
+ }
+ renderBody = () => {
+ const { prefixCls, title, closable } = this.props;
+ let header;
+ if (title) {
+ header = (
+
+ );
+ }
+ let closer;
+ if (closable) {
+ closer = (
+
+ );
+ }
+ const containerStyle = { width: this.props.width };
+ return (
+
+ {header}
+ {closer}
+
{this.props.children}
;
+
+ );
+ }
+ render() {
+ return (
+
+ {this.renderBody()}
+
+ );
+ }
+}
diff --git a/components/drawer/index.zh-CN.md b/components/drawer/index.zh-CN.md
new file mode 100644
index 0000000000..5d675ca0c9
--- /dev/null
+++ b/components/drawer/index.zh-CN.md
@@ -0,0 +1,32 @@
+---
+type: Feedback
+category: Components
+subtitle: 抽屉
+title: Drawer
+---
+
+抽屉容器
+
+## 何时使用
+
+
+## API
+
+| 参数 | 说明 | 类型 | 默认值 |
+| --- | --- | --- | --- |
+| closable | 是否显示右上角的关闭按钮 | boolean | true |
+| destroyOnClose | 关闭时销毁 Drawer 里的子元素 | boolean | false |
+| getContainer | 指定 Drawer 挂载的 HTML 节点 | (instance): HTMLElement | () => document.body |
+| maskClosable | 点击蒙层是否允许关闭 | boolean | true |
+| mask | 是否展示遮罩 | Boolean | true |
+| maskStyle | 遮罩样式 | object | {} |
+| style | 可用于设置 Drawer 的样式,调整浮层位置等 | object | - |
+| title | 标题 | string\|ReactNode | 无 |
+| visible | Drawer 是否可见 | boolean | 无 |
+| width | 宽度 | string\|number | 325 |
+| wrapClassName | 对话框外层容器的类名 | string | - |
+| zIndex | 设置 Drawer 的 `z-index` | Number | 1000 |
+| placement | 抽屉的方向 | 'left' | 'right' | 'left'
+| onClose | 点击遮罩层或右上角叉或取消按钮的回调 | function(e) | 无 |
+
+
diff --git a/components/drawer/style/drawer.less b/components/drawer/style/drawer.less
new file mode 100644
index 0000000000..dac3bf324e
--- /dev/null
+++ b/components/drawer/style/drawer.less
@@ -0,0 +1,237 @@
+@dawer-prefix-cls: ~"@{ant-prefix}-drawer";
+
+.@{dawer-prefix-cls} {
+ position: fixed;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+
+ &-content-wrapper {
+ position: absolute;
+ z-index: @zindex-modal-mask + 1;
+ }
+
+ &-left,
+ &-right {
+ .@{dawer-prefix-cls}-content-wrapper,
+ .@{dawer-prefix-cls}-content {
+ height: 100%;
+ }
+ }
+ &-left {
+ .@{dawer-prefix-cls} {
+ &-handle {
+ right: -40px;
+ box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);
+ border-radius: 0 4px 4px 0;
+ }
+ }
+ &.@{dawer-prefix-cls}-open {
+ .@{dawer-prefix-cls} {
+ &-wrapper {
+ box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);
+ }
+ }
+ }
+ }
+ &-right {
+ .@{dawer-prefix-cls} {
+ &-content-wrapper {
+ right: 0;
+ }
+ &-handle {
+ left: -40px;
+ box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15);
+ border-radius: 4px 0 0 4px;
+ }
+ }
+ &.@{dawer-prefix-cls}-open {
+ & .@{dawer-prefix-cls} {
+ &-wrapper {
+ box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15);
+ }
+ }
+ }
+ }
+ &-top,
+ &-bottom {
+ .@{dawer-prefix-cls}-content-wrapper,
+ .@{dawer-prefix-cls}-content {
+ width: 100%;
+ }
+ .@{dawer-prefix-cls} {
+ &-handle {
+ left: 50%;
+ margin-left: -20px;
+ }
+ }
+ }
+ &-top {
+ .@{dawer-prefix-cls} {
+ &-handle {
+ top: auto;
+ bottom: -40px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+ border-radius: 0 0 4px 4px;
+ }
+ }
+ &.@{dawer-prefix-cls}-open {
+ .@{dawer-prefix-cls} {
+ &-wrapper {
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+ }
+ }
+ }
+ }
+ &-bottom {
+ .@{dawer-prefix-cls} {
+ &-content-wrapper {
+ bottom: 0;
+ }
+ &-handle {
+ top: -40px;
+ box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.15);
+ border-radius: 4px 4px 0 0;
+ }
+ }
+ &.@{dawer-prefix-cls}-open {
+ .@{dawer-prefix-cls} {
+ &-wrapper {
+ box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.15);
+ }
+ }
+ }
+ }
+ &.@{dawer-prefix-cls}-open {
+ > * {
+ pointer-events: auto;
+ }
+ .@{dawer-prefix-cls} {
+ &-mask {
+ opacity: 0.3;
+ display: block;
+ }
+ &-handle {
+ &-icon {
+ background: transparent;
+ &:before {
+ transform: translateY(5px) rotate(45deg);
+ }
+ &:after {
+ transform: translateY(-5px) rotate(-45deg);
+ }
+ }
+ }
+ }
+ }
+
+ &-title {
+ margin: 0;
+ font-size: @font-size-lg;
+ line-height: 22px;
+ font-weight: 500;
+ color: @heading-color;
+ }
+
+ &-content {
+ position: relative;
+ background-color: @component-background;
+ border: 0;
+ background-clip: padding-box;
+ box-shadow: @shadow-2;
+ }
+
+ &-close {
+ cursor: pointer;
+ border: 0;
+ background: transparent;
+ position: absolute;
+ right: 0;
+ top: 0;
+ z-index: 10;
+ font-weight: 700;
+ line-height: 1;
+ text-decoration: none;
+ transition: color 0.3s;
+ color: @text-color-secondary;
+ outline: 0;
+ padding: 0;
+
+ &-x {
+ display: block;
+ font-style: normal;
+ text-align: center;
+ text-transform: none;
+ text-rendering: auto;
+ width: 56px;
+ height: 56px;
+ line-height: 56px;
+ font-size: @font-size-lg;
+
+ &:before {
+ content: "\e633";
+ display: block;
+ font-family: "anticon" !important;
+ }
+ }
+
+ &:focus,
+ &:hover {
+ color: #444;
+ text-decoration: none;
+ }
+ }
+
+ &-header {
+ padding: 16px 24px;
+ border-radius: @border-radius-base @border-radius-base 0 0;
+ background: @component-background;
+ color: @text-color;
+ border-bottom: @border-width-base @border-style-base @border-color-split;
+ }
+
+ &-body {
+ padding: 24px;
+ font-size: @font-size-base;
+ line-height: @line-height-base;
+ word-wrap: break-word;
+ }
+
+ &.zoom-enter,
+ &.zoom-appear {
+ animation-duration: @animation-duration-slow;
+ transform: none; // reset scale avoid mousePosition bug
+ opacity: 0;
+ }
+
+ &-mask {
+ position: fixed;
+ top: 0;
+ right: 0;
+ left: 0;
+ bottom: 0;
+ display: none;
+ background-color: #373737;
+ background-color: @modal-mask-bg; // lesshint duplicateProperty: false
+ height: 100%;
+ z-index: @zindex-modal-mask;
+ filter: ~"alpha(opacity=50)";
+ }
+
+ &-open {
+ overflow: hidden;
+ }
+}
+
+@media (max-width: @screen-md) {
+ .@{dawer-prefix-cls} {
+ width: auto !important;
+ margin: 10px;
+ }
+ .vertical-center-modal {
+ .@{dawer-prefix-cls} {
+ flex: 1;
+ }
+ }
+}
diff --git a/components/drawer/style/index.less b/components/drawer/style/index.less
new file mode 100644
index 0000000000..303b8ee832
--- /dev/null
+++ b/components/drawer/style/index.less
@@ -0,0 +1,4 @@
+@import "../../style/themes/default";
+@import "../../style/mixins/index";
+@import "./drawer";
+
diff --git a/components/drawer/style/index.tsx b/components/drawer/style/index.tsx
new file mode 100644
index 0000000000..416ec0177e
--- /dev/null
+++ b/components/drawer/style/index.tsx
@@ -0,0 +1,5 @@
+import '../../style/index.less';
+import './index.less';
+
+// style dependencies
+import '../../button/style';
diff --git a/components/index.tsx b/components/index.tsx
index 4a06cf350e..bbb3c7bebf 100644
--- a/components/index.tsx
+++ b/components/index.tsx
@@ -51,6 +51,8 @@ export { default as Divider } from './divider';
export { default as Dropdown } from './dropdown';
+export { default as Drawer } from './drawer';
+
export { default as Form } from './form';
export { default as Icon } from './icon';
diff --git a/package.json b/package.json
index 2ff0d6de24..1cb25feafc 100644
--- a/package.json
+++ b/package.json
@@ -143,7 +143,7 @@
"preact": "^8.2.5",
"preact-compat": "^3.17.0",
"querystring": "^0.2.0",
- "rc-drawer-menu": "^0.5.3",
+ "rc-drawer-menu": "^1.0.2",
"rc-queue-anim": "^1.4.1",
"rc-scroll-anim": "^2.2.1",
"rc-tween-one": "^2.0.1",
diff --git a/typings/custom-typings.d.ts b/typings/custom-typings.d.ts
index 3d3e1c46a3..83636f3c95 100644
--- a/typings/custom-typings.d.ts
+++ b/typings/custom-typings.d.ts
@@ -40,6 +40,8 @@ declare module 'rc-progress';
declare module 'rc-menu';
+declare module 'rc-drawer-menu';
+
declare module 'rc-tabs*';
declare module 'rc-tree';