import * as React from 'react'; import * as PropTypes from 'prop-types'; import RcDrawer from 'rc-drawer'; import createReactContext, { Context } from 'create-react-context'; import warning from 'warning'; import classNames from 'classnames'; import Icon from '../icon'; const DrawerContext: Context = createReactContext(null); type EventType = | React.MouseEvent | React.MouseEvent; type getContainerfunc = () => HTMLElement; type placementType = 'top' | 'right' | 'bottom' | 'left'; export interface DrawerProps { closable?: boolean; destroyOnClose?: boolean; getContainer?: string | HTMLElement | getContainerfunc; maskClosable?: boolean; mask?: boolean; maskStyle?: React.CSSProperties; style?: React.CSSProperties; title?: React.ReactNode; visible?: boolean; width?: number | string; height?: number | string; /* deprecated, use className instead */ wrapClassName?: string; zIndex?: number; prefixCls?: string; push?: boolean; placement?: placementType; onClose?: (e: EventType) => void; className?: string; } export interface IDrawerState { push?: boolean; } export default class Drawer extends React.Component { static propTypes = { closable: PropTypes.bool, destroyOnClose: PropTypes.bool, getContainer: PropTypes.oneOfType([ PropTypes.string, PropTypes.object, PropTypes.func, PropTypes.bool, ]), maskClosable: PropTypes.bool, mask: PropTypes.bool, maskStyle: PropTypes.object, style: PropTypes.object, title: PropTypes.node, visible: PropTypes.bool, width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), zIndex: PropTypes.number, prefixCls: PropTypes.string, placement: PropTypes.string, onClose: PropTypes.func, className: PropTypes.string, }; static defaultProps = { prefixCls: 'ant-drawer', width: 256, height: 256, closable: true, placement: 'right', maskClosable: true, level: null, }; readonly state = { push: false, }; parentDrawer: Drawer; destoryClose: boolean; public componentDidUpdate(preProps: DrawerProps) { if (preProps.visible !== this.props.visible && this.parentDrawer) { if (this.props.visible) { this.parentDrawer.push(); } else { this.parentDrawer.pull(); } } } close = (e: EventType) => { if (this.props.visible !== undefined) { if (this.props.onClose) { this.props.onClose(e); } return; } } onMaskClick = (e: EventType) => { if (!this.props.maskClosable) { return; } this.close(e); } push = () => { this.setState({ push: true, }); } pull = () => { this.setState({ push: false, }); } onDestoryTransitionEnd = () => { const isDestroyOnClose = this.getDestoryOnClose(); if (!isDestroyOnClose) { return; } if (!this.props.visible) { this.destoryClose = true; this.forceUpdate(); } } getDestoryOnClose = () => (this.props.destroyOnClose && !this.props.visible); // get drawar push width or height getPushTransform = (placement?: placementType) => { if (placement === 'left' || placement === 'right') { return `translateX(${placement === 'left' ? 180 : -180}px)`; } if (placement === 'top' || placement === 'bottom') { return `translateY(${placement === 'top' ? 180 : -180}px)`; } } // render drawer body dom renderBody = () => { if (this.destoryClose && !this.props.visible) { return null; } this.destoryClose = false; const { placement } = this.props; const containerStyle: React.CSSProperties = placement === 'left' || placement === 'right' ? { overflow: 'auto', height: '100%', } : {}; const isDestroyOnClose = this.getDestoryOnClose(); if (isDestroyOnClose) { // Increase the opacity transition, delete children after closing. containerStyle.opacity = 0; containerStyle.transition = 'opacity .3s'; } const { prefixCls, title, closable } = this.props; // is have header dom let header; if (title) { header = (
{title}
); } // is have closer button let closer; if (closable) { closer = ( ); } return (
{header} {closer}
{this.props.children}
); } getRcDrawerStyle = () => { const { zIndex, placement, maskStyle } = this.props; return this.state.push ? { ...maskStyle, zIndex, transform: this.getPushTransform(placement), } : { ...maskStyle, zIndex, }; } // render Provider for Multi-level drawe renderProvider = (value: Drawer) => { let { zIndex, style, placement, className, wrapClassName, width, height, ...rest } = this.props; warning(wrapClassName === undefined, 'wrapClassName is deprecated, please use className instead.'); this.parentDrawer = value; const offsetStyle: any = {}; if (placement === 'left' || placement === 'right') { offsetStyle.width = width; } else { offsetStyle.height = height; } return ( {this.renderBody()} ); } render() { return ( {this.renderProvider} ); } }