2020-03-02 12:09:38 +08:00
|
|
|
|
import CloseOutlined from '@ant-design/icons/CloseOutlined';
|
2018-08-05 07:08:34 +08:00
|
|
|
|
import classNames from 'classnames';
|
2022-05-25 11:03:13 +08:00
|
|
|
|
import RcDrawer from 'rc-drawer';
|
2022-07-25 21:04:43 +08:00
|
|
|
|
import type { DrawerProps as RcDrawerProps } from 'rc-drawer';
|
|
|
|
|
import type { CSSMotionProps } from 'rc-motion';
|
2022-05-25 11:03:13 +08:00
|
|
|
|
import * as React from 'react';
|
2022-03-23 22:46:15 +08:00
|
|
|
|
import { ConfigContext } from '../config-provider';
|
2022-06-06 23:39:00 +08:00
|
|
|
|
import { NoFormStyle } from '../form/context';
|
2022-07-25 21:04:43 +08:00
|
|
|
|
import { getTransitionName } from '../_util/motion';
|
2018-12-22 21:21:42 +08:00
|
|
|
|
import { tuple } from '../_util/type';
|
2022-08-23 16:22:00 +08:00
|
|
|
|
import warning from '../_util/warning';
|
2018-07-02 21:49:06 +08:00
|
|
|
|
|
2022-03-24 23:33:51 +08:00
|
|
|
|
// CSSINJS
|
|
|
|
|
import useStyle from './style';
|
|
|
|
|
|
2021-06-11 08:39:17 +08:00
|
|
|
|
const SizeTypes = tuple('default', 'large');
|
|
|
|
|
type sizeType = typeof SizeTypes[number];
|
|
|
|
|
|
2020-07-12 18:47:14 +08:00
|
|
|
|
export interface PushState {
|
|
|
|
|
distance: string | number;
|
|
|
|
|
}
|
2022-08-01 17:06:19 +08:00
|
|
|
|
|
|
|
|
|
// Drawer diff props: 'open' | 'motion' | 'maskMotion' | 'wrapperClassName'
|
|
|
|
|
export interface DrawerProps extends RcDrawerProps {
|
|
|
|
|
size?: sizeType;
|
2018-05-23 10:56:37 +08:00
|
|
|
|
closable?: boolean;
|
2020-06-08 19:24:29 +08:00
|
|
|
|
closeIcon?: React.ReactNode;
|
2022-08-01 17:06:19 +08:00
|
|
|
|
|
2020-12-28 15:30:18 +08:00
|
|
|
|
/** Wrapper dom node style of header and body */
|
2019-10-07 18:58:10 +08:00
|
|
|
|
drawerStyle?: React.CSSProperties;
|
|
|
|
|
headerStyle?: React.CSSProperties;
|
2019-01-11 22:45:01 +08:00
|
|
|
|
bodyStyle?: React.CSSProperties;
|
2022-08-01 17:06:19 +08:00
|
|
|
|
footerStyle?: React.CSSProperties;
|
|
|
|
|
|
2018-05-23 10:56:37 +08:00
|
|
|
|
title?: React.ReactNode;
|
2022-08-23 16:22:00 +08:00
|
|
|
|
open?: boolean;
|
2022-08-01 17:06:19 +08:00
|
|
|
|
|
2020-01-06 14:56:00 +08:00
|
|
|
|
footer?: React.ReactNode;
|
2022-08-01 17:06:19 +08:00
|
|
|
|
extra?: React.ReactNode;
|
|
|
|
|
|
2022-08-23 16:22:00 +08:00
|
|
|
|
afterOpenChange?: (open: boolean) => void;
|
2022-09-06 21:46:49 +08:00
|
|
|
|
|
|
|
|
|
// Deprecated
|
|
|
|
|
/** @deprecated Please use `open` instead */
|
|
|
|
|
visible?: boolean;
|
|
|
|
|
/** @deprecated Please use `afterOpenChange` instead */
|
|
|
|
|
afterVisibleChange?: (open: boolean) => void;
|
2020-10-24 14:47:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-12 18:47:14 +08:00
|
|
|
|
const defaultPushState: PushState = { distance: 180 };
|
2019-07-17 19:55:59 +08:00
|
|
|
|
|
2022-08-23 16:22:00 +08:00
|
|
|
|
function Drawer(props: DrawerProps) {
|
|
|
|
|
const {
|
|
|
|
|
rootClassName,
|
|
|
|
|
width,
|
|
|
|
|
height,
|
|
|
|
|
size = 'default',
|
|
|
|
|
closable = true,
|
|
|
|
|
mask = true,
|
|
|
|
|
push = defaultPushState,
|
|
|
|
|
closeIcon = <CloseOutlined />,
|
|
|
|
|
bodyStyle,
|
|
|
|
|
drawerStyle,
|
|
|
|
|
open,
|
2022-09-06 21:46:49 +08:00
|
|
|
|
afterOpenChange,
|
2022-08-23 16:22:00 +08:00
|
|
|
|
children,
|
|
|
|
|
title,
|
|
|
|
|
headerStyle,
|
|
|
|
|
onClose,
|
|
|
|
|
footer,
|
|
|
|
|
footerStyle,
|
|
|
|
|
prefixCls: customizePrefixCls,
|
|
|
|
|
getContainer: customizeGetContainer,
|
|
|
|
|
extra,
|
2022-09-06 21:46:49 +08:00
|
|
|
|
|
|
|
|
|
// Deprecated
|
|
|
|
|
visible,
|
|
|
|
|
afterVisibleChange,
|
|
|
|
|
|
2022-08-23 16:22:00 +08:00
|
|
|
|
...rest
|
|
|
|
|
} = props;
|
|
|
|
|
|
2022-07-25 21:04:43 +08:00
|
|
|
|
const { getPopupContainer, getPrefixCls, direction } = React.useContext(ConfigContext);
|
|
|
|
|
const prefixCls = getPrefixCls('drawer', customizePrefixCls);
|
|
|
|
|
|
2022-07-29 15:56:11 +08:00
|
|
|
|
// Style
|
|
|
|
|
const [wrapSSR, hashId] = useStyle(prefixCls);
|
|
|
|
|
|
2022-07-25 21:04:43 +08:00
|
|
|
|
const getContainer =
|
|
|
|
|
// 有可能为 false,所以不能直接判断
|
|
|
|
|
customizeGetContainer === undefined && getPopupContainer
|
|
|
|
|
? () => getPopupContainer(document.body)
|
|
|
|
|
: customizeGetContainer;
|
|
|
|
|
|
|
|
|
|
const closeIconNode = closable && (
|
|
|
|
|
<button type="button" onClick={onClose} aria-label="Close" className={`${prefixCls}-close`}>
|
|
|
|
|
{closeIcon}
|
|
|
|
|
</button>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
function renderHeader() {
|
|
|
|
|
if (!title && !closable) {
|
|
|
|
|
return null;
|
2020-01-06 14:56:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-07-25 21:04:43 +08:00
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className={classNames(`${prefixCls}-header`, {
|
|
|
|
|
[`${prefixCls}-header-close-only`]: closable && !title && !extra,
|
|
|
|
|
})}
|
|
|
|
|
style={headerStyle}
|
|
|
|
|
>
|
|
|
|
|
<div className={`${prefixCls}-header-title`}>
|
|
|
|
|
{closeIconNode}
|
|
|
|
|
{title && <div className={`${prefixCls}-title`}>{title}</div>}
|
2021-02-05 10:47:17 +08:00
|
|
|
|
</div>
|
2022-07-25 21:04:43 +08:00
|
|
|
|
{extra && <div className={`${prefixCls}-extra`}>{extra}</div>}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function renderFooter() {
|
|
|
|
|
if (!footer) {
|
|
|
|
|
return null;
|
2018-07-19 15:39:47 +08:00
|
|
|
|
}
|
2018-07-22 11:27:48 +08:00
|
|
|
|
|
2022-07-25 21:04:43 +08:00
|
|
|
|
const footerClassName = `${prefixCls}-footer`;
|
|
|
|
|
return (
|
|
|
|
|
<div className={footerClassName} style={footerStyle}>
|
|
|
|
|
{footer}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
2018-07-18 15:52:51 +08:00
|
|
|
|
|
2022-07-25 21:04:43 +08:00
|
|
|
|
const drawerClassName = classNames(
|
|
|
|
|
{
|
|
|
|
|
'no-mask': !mask,
|
|
|
|
|
[`${prefixCls}-rtl`]: direction === 'rtl',
|
|
|
|
|
},
|
2022-08-01 23:20:04 +08:00
|
|
|
|
rootClassName,
|
2022-07-29 15:56:11 +08:00
|
|
|
|
hashId,
|
2022-07-25 21:04:43 +08:00
|
|
|
|
);
|
|
|
|
|
|
2022-08-23 16:22:00 +08:00
|
|
|
|
// ========================== Warning ===========================
|
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
|
|
|
[
|
|
|
|
|
['visible', 'open'],
|
|
|
|
|
['afterVisibleChange', 'afterOpenChange'],
|
|
|
|
|
].forEach(([deprecatedName, newName]) => {
|
|
|
|
|
warning(
|
|
|
|
|
!(deprecatedName in props),
|
|
|
|
|
'Drawer',
|
2022-09-06 21:46:49 +08:00
|
|
|
|
`\`${deprecatedName}\` is deprecated, please use \`${newName}\` instead.`,
|
2022-08-23 16:22:00 +08:00
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-25 21:04:43 +08:00
|
|
|
|
// ============================ Size ============================
|
|
|
|
|
const mergedWidth = React.useMemo(() => width ?? (size === 'large' ? 736 : 378), [width, size]);
|
|
|
|
|
const mergedHeight = React.useMemo(
|
|
|
|
|
() => height ?? (size === 'large' ? 736 : 378),
|
|
|
|
|
[height, size],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// =========================== Motion ===========================
|
|
|
|
|
const maskMotion: CSSMotionProps = {
|
|
|
|
|
motionName: getTransitionName(prefixCls, 'mask-motion'),
|
|
|
|
|
motionAppear: true,
|
|
|
|
|
motionEnter: true,
|
|
|
|
|
motionLeave: true,
|
2022-08-17 11:16:01 +08:00
|
|
|
|
motionDeadline: 500,
|
2022-07-25 21:04:43 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const panelMotion: RcDrawerProps['motion'] = motionPlacement => ({
|
|
|
|
|
motionName: getTransitionName(prefixCls, `panel-motion-${motionPlacement}`),
|
|
|
|
|
motionAppear: true,
|
|
|
|
|
motionEnter: true,
|
|
|
|
|
motionLeave: true,
|
2022-08-17 11:16:01 +08:00
|
|
|
|
motionDeadline: 500,
|
2022-07-25 21:04:43 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// =========================== Render ===========================
|
2022-07-29 15:56:11 +08:00
|
|
|
|
return wrapSSR(
|
2022-07-25 21:04:43 +08:00
|
|
|
|
<NoFormStyle status override>
|
|
|
|
|
<RcDrawer
|
|
|
|
|
prefixCls={prefixCls}
|
|
|
|
|
onClose={onClose}
|
2022-08-01 23:20:04 +08:00
|
|
|
|
maskMotion={maskMotion}
|
|
|
|
|
motion={panelMotion}
|
2022-07-25 21:04:43 +08:00
|
|
|
|
{...rest}
|
2022-09-06 21:46:49 +08:00
|
|
|
|
open={open ?? visible}
|
2022-07-25 21:04:43 +08:00
|
|
|
|
mask={mask}
|
|
|
|
|
push={push}
|
|
|
|
|
width={mergedWidth}
|
|
|
|
|
height={mergedHeight}
|
|
|
|
|
rootClassName={drawerClassName}
|
|
|
|
|
getContainer={getContainer}
|
2022-09-06 21:46:49 +08:00
|
|
|
|
afterOpenChange={afterOpenChange ?? afterVisibleChange}
|
2022-07-25 21:04:43 +08:00
|
|
|
|
>
|
2022-05-16 10:14:26 +08:00
|
|
|
|
<div className={`${prefixCls}-wrapper-body`} style={{ ...drawerStyle }}>
|
2021-02-05 10:47:17 +08:00
|
|
|
|
{renderHeader()}
|
|
|
|
|
<div className={`${prefixCls}-body`} style={bodyStyle}>
|
|
|
|
|
{children}
|
|
|
|
|
</div>
|
|
|
|
|
{renderFooter()}
|
2019-01-11 22:45:01 +08:00
|
|
|
|
</div>
|
2022-07-25 21:04:43 +08:00
|
|
|
|
</RcDrawer>
|
2022-07-29 15:56:11 +08:00
|
|
|
|
</NoFormStyle>,
|
2022-07-25 21:04:43 +08:00
|
|
|
|
);
|
|
|
|
|
}
|
2020-10-24 14:47:44 +08:00
|
|
|
|
|
2022-06-21 10:24:52 +08:00
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
|
|
|
Drawer.displayName = 'Drawer';
|
|
|
|
|
}
|
2019-01-03 17:10:04 +08:00
|
|
|
|
|
2022-08-25 10:17:29 +08:00
|
|
|
|
function PurePanel({ style, ...restProps }: DrawerProps) {
|
2022-08-01 23:20:04 +08:00
|
|
|
|
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
ref={containerRef}
|
|
|
|
|
style={{
|
|
|
|
|
position: 'relative',
|
|
|
|
|
minHeight: 100,
|
|
|
|
|
overflow: 'hidden',
|
|
|
|
|
...style,
|
|
|
|
|
}}
|
|
|
|
|
>
|
2022-08-23 16:22:00 +08:00
|
|
|
|
<Drawer {...restProps} getContainer={false} maskMotion={{}} motion={{}} open />
|
2022-08-01 23:20:04 +08:00
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Drawer._InternalPanelDoNotUseOrYouWillBeFired = PurePanel;
|
|
|
|
|
|
2022-03-23 22:46:15 +08:00
|
|
|
|
export default Drawer;
|