Skip to content

fix(slidepane): add two types and close ways #505

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions src/drawer/__tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { fireEvent, render } from '@testing-library/react';
import { alert } from 'ant-design-testing';
import '@testing-library/jest-dom/extend-expect';

import Drawer from '../index';
import Drawer, { DrawerType } from '../index';

describe('test Drawer ', () => {
test('snapshot match', () => {
Expand All @@ -27,18 +27,23 @@ describe('test Drawer ', () => {
const domLoading = document.querySelector('.ant-spin-spinning');
expect(domLoading).not.toBe(null);
});
test('should render mask correct ', () => {
test('should render mask/maskClosable correct', () => {
const { unmount } = render(<Drawer open>Hello World</Drawer>);
const dom = document.querySelector('.dtc-drawer-mask');
expect(dom).toBe(null);
unmount();
const fn = jest.fn();
render(
<Drawer open mask>
<Drawer open mask maskClosable onClose={fn}>
Hello World
</Drawer>
);
const domMask = document.querySelector('.dtc-drawer-mask');
const domIcon = document.querySelector('.dtc-drawer-header--icon');
expect(domMask).not.toBe(null);
expect(domIcon).toBe(null);
fireEvent.click(domMask as Element);
expect(fn).toHaveBeenCalledTimes(1);
});
test('should render width correct', () => {
render(
Expand Down Expand Up @@ -171,4 +176,19 @@ describe('test Drawer ', () => {
fireEvent.click(oImg);
expect(fn).toHaveBeenCalledTimes(1);
});

test('should render from type', () => {
const fn = jest.fn();
render(
<Drawer open type={DrawerType.Form} title="title" onClose={fn}>
Hello World
</Drawer>
);
const mask = document.querySelector('.dtc-drawer-mask');
expect(mask).not.toBe(null);
const domIcon = document.querySelector('.dtc-drawer-header--icon');
expect(domIcon).not.toBe(null);
fireEvent.click(mask as Element);
expect(fn).toHaveBeenCalledTimes(0);
});
});
36 changes: 0 additions & 36 deletions src/drawer/demos/basic_mask.tsx

This file was deleted.

34 changes: 34 additions & 0 deletions src/drawer/demos/basic_two.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, { useState } from 'react';
import { Button } from 'antd';
import { Drawer } from 'dt-react-component';
import { DrawerType } from 'dt-react-component/drawer';

export default () => {
const [firstVisible, setFirstVisible] = useState(false);
const [secondVisible, setSecondVisible] = useState(false);

return (
<>
<Button
style={{ margin: '10px' }}
onClick={() => {
setFirstVisible(true);
}}
>
click me
</Button>
<Drawer open={firstVisible} onClose={() => setFirstVisible(false)} title="一级弹窗">
<div>一级弹窗</div>
<Button onClick={() => setSecondVisible(true)}>打开二级弹窗</Button>
<Drawer
open={secondVisible}
onClose={() => setSecondVisible(false)}
title="二级弹窗"
type={DrawerType.Form}
>
<div>一级弹窗</div>
</Drawer>
</Drawer>
</>
);
};
52 changes: 52 additions & 0 deletions src/drawer/demos/basic_type.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { useState } from 'react';
import { Button, Space, Switch } from 'antd';
import { Drawer } from 'dt-react-component';
import { DrawerType } from 'dt-react-component/drawer';

export default () => {
const [visible, setVisible] = useState(false);
const [mask, setMask] = useState(false);
const [maskClosable, setMaskClosable] = useState(false);
const [type, setType] = useState(DrawerType.Normal);

return (
<>
<Space>
<Button
type="primary"
onClick={() => {
setVisible(true);
setType(DrawerType.Form);
}}
>
Form 类型
</Button>
<Button
type="primary"
onClick={() => {
setVisible(true);
setType(DrawerType.Normal);
}}
>
正常类型
</Button>
</Space>
<Space>
mask:
<Switch onChange={(checked) => setMask(checked)} />
maskClosable:
<Switch onChange={(checked) => setMaskClosable(checked)} />
</Space>
<Drawer
open={visible}
onClose={() => setVisible(false)}
title="title"
mask={mask}
maskClosable={maskClosable}
type={type}
>
<div>hello world</div>
</Drawer>
</>
);
};
30 changes: 16 additions & 14 deletions src/drawer/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ demo:
## 示例

<code src="./demos/basic.tsx" title="基础使用"></code>
<code src="./demos/basic_mask.tsx" title="基础 mask 使用"></code>
<code src="./demos/basic_type.tsx" title="两种类型的 SlidePane" description="表单类型默认展示`mask`且不可点击关闭,且不可配置;正常类型默认不展示`mask`,`mask | maskClosable`可以配置"></code>
<code src="./demos/basicSize.tsx" title="尺寸"></code>
<code src="./demos/basic_top.tsx" title="抽屉距顶部高度"></code>
<code src="./demos/customTitle.tsx" title="自定义 Title"></code>
Expand All @@ -25,26 +25,28 @@ demo:
<code src="./demos/footer.tsx" title="展示 footer"></code>
<code src="./demos/basicBanner.tsx" title="支持 banner"></code>
<code src="./demos/basicBannerProps.tsx" title="支持传 banner 的 Props 属性"></code>
<code src="./demos/basic_two.tsx" title="二级弹窗"></code>

## API

### AlertProps

[AlertProps](https://4x-ant-design.antgroup.com/components/alert-cn/#API)

| 参数 | 说明 | 类型 | 默认值 |
| ------------- | ---------------------------------- | ----------------------------------------------------- | --------- |
| activeKey | 右侧面板的内容的 Tabs 的选中项 | `string` | - |
| banner | 提示 | `React.ReactNode \| AlertProps` | - |
| bodyClassName | 内容容器的类名 | `string` | - |
| bodyStyle | 内容容器的样式 | `CSSProperties` | - |
| children | 右侧面板展示内容 | `(key: string) => React.ReactNode \| React.ReactNode` | - |
| defaultKey | 右侧面板的内容的 Tabs 的默认选中项 | `string` | - |
| footer | 右侧面板的底部内容 | `React.ReactNode` | - |
| size | 尺寸 | `small \| default \| large` | `default` |
| tabs | 右侧面板的内容的 Tabs | `{ key: string; title: React.ReactNode }[]` | - |
| title | 右侧面板的 title | `React.ReactNode` | - |
| onChange | 右侧面板的 Tabs 切换回调 | `(key: string) => void` | - |
| 参数 | 说明 | 类型 | 默认值 |
| ------------- | ---------------------------------- | ----------------------------------------------------- | ---------------------- |
| activeKey | 右侧面板的内容的 Tabs 的选中项 | `string` | - |
| banner | 提示 | `React.ReactNode \| AlertProps` | - |
| bodyClassName | 内容容器的类名 | `string` | - |
| bodyStyle | 内容容器的样式 | `CSSProperties` | - |
| children | 右侧面板展示内容 | `(key: string) => React.ReactNode \| React.ReactNode` | - |
| defaultKey | 右侧面板的内容的 Tabs 的默认选中项 | `string` | - |
| footer | 右侧面板的底部内容 | `React.ReactNode` | - |
| size | 尺寸 | `small \| default \| large` | `default` |
| tabs | 右侧面板的内容的 Tabs | `{ key: string; title: React.ReactNode }[]` | - |
| title | 右侧面板的 title | `React.ReactNode` | - |
| type | 右侧面板的类型 | `SlidePaneType.Form \| SlidePaneType.Normal` | `SlidePaneType.Normal` |
| onChange | 右侧面板的 Tabs 切换回调 | `(key: string) => void` | - |

:::info
其余属性继承 [antd4.x 的 Drawer](https://4x.ant.design/components/drawer-cn/#API)
Expand Down
39 changes: 28 additions & 11 deletions src/drawer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { CSSProperties, useEffect, useState } from 'react';
import { CloseOutlined } from '@ant-design/icons';
import { Alert, AlertProps, Spin, Tabs } from 'antd';
import classNames from 'classnames';
import { omit } from 'lodash';
Expand All @@ -16,16 +17,20 @@ type readOnlyTab = readonly Tab[];

type TabKey<T extends readOnlyTab> = T[number]['key'];

export enum DrawerType {
Form = 'form',
Normal = 'normal',
}

interface NormalDrawerProps extends Omit<AntdDrawerProps, 'placement'> {
/** @deprecated */
visible?: boolean;
size?: 'small' | 'default' | 'large';
loading?: boolean;
bodyClassName?: string;
title?: React.ReactNode;
bodyStyle?: CSSProperties;
footer?: React.ReactNode;
banner?: AlertProps['message'] | Omit<AlertProps, 'banner'>;
type?: DrawerType;
}

interface TabsDrawerProps<T extends readOnlyTab> extends Omit<NormalDrawerProps, 'children'> {
Expand Down Expand Up @@ -65,31 +70,32 @@ const Drawer = <T extends readOnlyTab>(props: DrawerProps<T>) => {
const slidePrefixCls = 'dtc-drawer';

const {
visible,
open,
loading = false,
bodyClassName,
mask = false,
maskClosable = true,
bodyStyle,
title,
width,
type = DrawerType.Normal,
size = 'default',
footer,
banner,
onClose,
...rest
} = props;

const composeOpen = open || visible;
const finalWidth = width ?? getWidthFromSize(size);
const isFormType = type === DrawerType.Form;

const [internalTabKey, setInternalTabKey] = useState('');

useEffect(() => {
composeOpen &&
open &&
isTabMode(props) &&
setInternalTabKey(props.defaultKey ?? props.tabs?.[0]?.key ?? '');
}, [composeOpen]);
}, [open]);

const currentKey = isControlled(props) ? props.activeKey : internalTabKey;

Expand All @@ -111,21 +117,32 @@ const Drawer = <T extends readOnlyTab>(props: DrawerProps<T>) => {

return (
<RcDrawer
open={composeOpen}
open={open}
placement="right"
mask={mask}
mask={isFormType ? true : mask}
maskClosable={isFormType ? false : maskClosable}
width={finalWidth}
prefixCls={slidePrefixCls}
onClose={onClose}
{...rest}
{...motionProps}
>
{!mask && renderButton()}
{!isFormType && renderButton()}
<Spin wrapperClassName={`${slidePrefixCls}-nested-loading`} spinning={loading}>
{title && <div className={`${slidePrefixCls}-header`}>{title}</div>}
{title && (
<div className={`${slidePrefixCls}-header`}>
{title}
{isFormType && (
<CloseOutlined
className={`${slidePrefixCls}-header--icon`}
onClick={onClose}
/>
)}
</div>
)}
{banner && (
<Alert
message={isValidBanner(banner) ? banner : banner.message}
message={isValidBanner(banner) ? banner : (banner as any).message}
banner
{...(isValidBanner(banner) ? {} : omit(banner, 'message'))}
/>
Expand Down
7 changes: 7 additions & 0 deletions src/drawer/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,19 @@ $prefix: "dtc-drawer";
pointer-events: auto;
}
&-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px;
background-color: #F9F9FA;
color: #3D446E;
font-weight: 500;
font-size: 14px;
line-height: 22px;
&--icon {
color: #64698B;
font-size: 16px;
}
}
&-tabs {
&.ant-tabs {
Expand Down
Loading