Skip to content

Commit

Permalink
feat: Drawer add loading prop to show spinner (#48563)
Browse files Browse the repository at this point in the history
* feat: Drawer add loading prop to show spinner

* fix: loading replace drawer content while true

* fix: update snap

* fix: update site snap

* fix: increase test coverage

* fix: upate check-site snap

---------

Co-authored-by: ykryshtal <ykryshtal@magnite.com>
  • Loading branch information
Enigama and EnigamaE committed Apr 29, 2024
1 parent ba5f9fe commit 6f6868f
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 0 deletions.
32 changes: 32 additions & 0 deletions components/drawer/DrawerPanel.tsx
Expand Up @@ -5,6 +5,8 @@ import type { DrawerProps as RCDrawerProps } from 'rc-drawer';
import useClosable, { pickClosable } from '../_util/hooks/useClosable';
import type { ClosableType } from '../_util/hooks/useClosable';
import { ConfigContext } from '../config-provider';
import Spin from '../spin';
import type { SpinProps } from '../spin';

export interface DrawerClassNames extends NonNullable<RCDrawerProps['classNames']> {
header?: string;
Expand Down Expand Up @@ -38,6 +40,7 @@ export interface DrawerPanelProps {
children?: React.ReactNode;
classNames?: DrawerClassNames;
styles?: DrawerStyles;
loading?: boolean | Omit<SpinProps, 'fullscreen' | 'tip'>;

/** @deprecated Please use `styles.header` instead */
headerStyle?: React.CSSProperties;
Expand All @@ -59,6 +62,7 @@ const DrawerPanel: React.FC<DrawerPanelProps> = (props) => {
title,
footer,
extra,
loading,
onClose,
headerStyle,
bodyStyle,
Expand Down Expand Up @@ -87,6 +91,19 @@ const DrawerPanel: React.FC<DrawerPanelProps> = (props) => {
},
);

// >>>>>>>>> Spinning
let spinProps: SpinProps | undefined;
if (typeof loading === 'boolean') {
spinProps = {
spinning: loading,
};
} else if (typeof loading === 'object') {
spinProps = {
spinning: true,
...loading,
};
}

const headerNode = React.useMemo<React.ReactNode>(() => {
if (!title && !mergedClosable) {
return null;
Expand Down Expand Up @@ -139,6 +156,21 @@ const DrawerPanel: React.FC<DrawerPanelProps> = (props) => {
);
}, [footer, footerStyle, prefixCls]);

if (spinProps?.spinning) {
return (
<Spin
spinning={false}
style={{
height: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
{...spinProps}
/>
);
}

return (
<>
{headerNode}
Expand Down
29 changes: 29 additions & 0 deletions components/drawer/__tests__/Drawer.test.tsx
Expand Up @@ -178,6 +178,35 @@ describe('Drawer', () => {
expect(baseElement.querySelectorAll('button.forceRender').length).toBe(1);
});

describe('Drawer loading', () => {
it('have a spinner', () => {
const { container: wrapper } = render(
<Drawer open loading getContainer={false}>
Here is content of Drawer
</Drawer>,
);

triggerMotion();
expect(wrapper.firstChild).toMatchSnapshot();
});
it('have a custom loading', () => {
const loadingContent = 'Custom Loading...';
const { container: wrapper } = render(
<Drawer
open
loading={{ indicator: <span>{loadingContent}</span>, spinning: true }}
getContainer={false}
>
Here is content of Drawer
</Drawer>,
);

triggerMotion();
const [loadingWrapper] = wrapper.getElementsByClassName('ant-spin-dot');
expect(loadingWrapper).toHaveTextContent(loadingContent);
});
});

it('support closeIcon', () => {
const { container: wrapper } = render(
<Drawer open closable closeIcon={<span>close</span>} width={400} getContainer={false}>
Expand Down
57 changes: 57 additions & 0 deletions components/drawer/__tests__/__snapshots__/Drawer.test.tsx.snap
@@ -1,5 +1,62 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Drawer Drawer loading have a spinner 1`] = `
<div
class="ant-drawer ant-drawer-right ant-drawer-open ant-drawer-inline"
tabindex="-1"
>
<div
class="ant-drawer-mask"
/>
<div
aria-hidden="true"
data-sentinel="start"
style="width: 0px; height: 0px; overflow: hidden; outline: none; position: absolute;"
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper"
style="width: 378px;"
>
<div
aria-modal="true"
class="ant-drawer-content"
role="dialog"
>
<div
aria-busy="true"
aria-live="polite"
class="ant-spin ant-spin-spinning"
style="height: 100%; display: flex; justify-content: center; align-items: center;"
>
<span
class="ant-spin-dot ant-spin-dot-spin"
>
<i
class="ant-spin-dot-item"
/>
<i
class="ant-spin-dot-item"
/>
<i
class="ant-spin-dot-item"
/>
<i
class="ant-spin-dot-item"
/>
</span>
</div>
</div>
</div>
<div
aria-hidden="true"
data-sentinel="end"
style="width: 0px; height: 0px; overflow: hidden; outline: none; position: absolute;"
tabindex="0"
/>
</div>
`;

exports[`Drawer className is test_drawer 1`] = `
<div
class="ant-drawer ant-drawer-right test_drawer ant-drawer-open ant-drawer-inline"
Expand Down
Expand Up @@ -2781,6 +2781,75 @@ Array [

exports[`renders components/drawer/demo/form-in-drawer.tsx extend context correctly 2`] = `[]`;

exports[`renders components/drawer/demo/loading.tsx extend context correctly 1`] = `
Array [
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open
</span>
</button>,
<div
class="ant-drawer ant-drawer-right ant-drawer-open ant-drawer-inline"
tabindex="-1"
>
<div
class="ant-drawer-mask"
/>
<div
aria-hidden="true"
data-sentinel="start"
style="width: 0px; height: 0px; overflow: hidden; outline: none; position: absolute;"
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper"
style="width: 378px;"
>
<div
aria-modal="true"
class="ant-drawer-content"
role="dialog"
>
<div
aria-busy="true"
aria-live="polite"
class="ant-spin ant-spin-spinning"
style="height: 100%; display: flex; justify-content: center; align-items: center;"
>
<span
class="ant-spin-dot ant-spin-dot-spin"
>
<i
class="ant-spin-dot-item"
/>
<i
class="ant-spin-dot-item"
/>
<i
class="ant-spin-dot-item"
/>
<i
class="ant-spin-dot-item"
/>
</span>
</div>
</div>
</div>
<div
aria-hidden="true"
data-sentinel="end"
style="width: 0px; height: 0px; overflow: hidden; outline: none; position: absolute;"
tabindex="0"
/>
</div>,
]
`;

exports[`renders components/drawer/demo/loading.tsx extend context correctly 2`] = `[]`;

exports[`renders components/drawer/demo/multi-level-drawer.tsx extend context correctly 1`] = `
Array [
<button
Expand Down
11 changes: 11 additions & 0 deletions components/drawer/__tests__/__snapshots__/demo.test.ts.snap
Expand Up @@ -259,6 +259,17 @@ exports[`renders components/drawer/demo/form-in-drawer.tsx correctly 1`] = `
</button>
`;

exports[`renders components/drawer/demo/loading.tsx correctly 1`] = `
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open
</span>
</button>
`;

exports[`renders components/drawer/demo/multi-level-drawer.tsx correctly 1`] = `
<button
class="ant-btn ant-btn-primary"
Expand Down
7 changes: 7 additions & 0 deletions components/drawer/demo/loading.md
@@ -0,0 +1,7 @@
## zh-CN

设置抽屉加载状态。

## en-US

Set the loading status of Drawer.
54 changes: 54 additions & 0 deletions components/drawer/demo/loading.tsx
@@ -0,0 +1,54 @@
import React, { useEffect, useState } from 'react';
import type { DrawerProps } from 'antd';
import { Button, Drawer } from 'antd';

const App: React.FC = () => {
const [open, setOpen] = useState(false);
const [loading, setLoading] = useState<DrawerProps['loading']>(true);
let id: NodeJS.Timer;

const showDrawer = () => {
setOpen(true);
};

const onClose = () => {
setOpen(false);
clearTimeout(Number(id));
};

useEffect(() => {
setLoading(true);
}, []);

useEffect(() => {
if (open) {
id = setTimeout(() => {
setLoading(false);
}, 1000);
}
}, [open]);

return (
<>
<Button type="primary" onClick={showDrawer}>
Open
</Button>
<Drawer
title="Basic Drawer"
placement="right"
closable={false}
onClose={onClose}
open={open}
loading={loading}
afterOpenChange={(visible) => !visible && setLoading(true)}
>
<Button onClick={() => setLoading(true)}>set Loading true</Button>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</Drawer>
</>
);
};

export default App;
2 changes: 2 additions & 0 deletions components/drawer/index.en-US.md
Expand Up @@ -22,6 +22,7 @@ A Drawer is a panel that is typically overlaid on top of a page and slides in fr
<!-- prettier-ignore -->
<code src="./demo/basic-right.tsx">Basic</code>
<code src="./demo/placement.tsx">Custom Placement</code>
<code src="./demo/loading.tsx">Loading</code>
<code src="./demo/extra.tsx">Extra Actions</code>
<code src="./demo/render-in-current.tsx">Render in current dom</code>
<code src="./demo/form-in-drawer.tsx">Submit form in drawer</code>
Expand Down Expand Up @@ -68,6 +69,7 @@ v5 use `rootClassName` & `rootStyle` to config wrapper style instead of `classNa
| styles | Semantic structure style | [Record<SemanticDOM, CSSProperties>](#semantic-dom) | - | 5.10.0 |
| size | preset size of drawer, default `378px` and large `736px` | 'default' \| 'large' | 'default' | 4.17.0 |
| title | The title for Drawer | ReactNode | - | |
| loading | Show spinning indicator | boolean \| `Omit<SpinProp, 'fullScreen' \| 'tip'>` | false | 5.17.0 |
| open | Whether the Drawer dialog is visible or not | boolean | false | |
| width | Width of the Drawer dialog | string \| number | 378 | |
| zIndex | The `z-index` of the Drawer | number | 1000 | |
Expand Down
2 changes: 2 additions & 0 deletions components/drawer/index.zh-CN.md
Expand Up @@ -22,6 +22,7 @@ demo:
<!-- prettier-ignore -->
<code src="./demo/basic-right.tsx">基础抽屉</code>
<code src="./demo/placement.tsx">自定义位置</code>
<code src="./demo/loading.tsx">加载中</code>
<code src="./demo/extra.tsx">额外操作</code>
<code src="./demo/render-in-current.tsx">渲染在当前 DOM</code>
<code src="./demo/form-in-drawer.tsx">抽屉表单</code>
Expand Down Expand Up @@ -67,6 +68,7 @@ v5 使用 `rootClassName` 与 `rootStyle` 来配置最外层元素样式。原 v
| style | 设计 Drawer 容器样式,如果你只需要设置内容部分请使用 `bodyStyle` | CSSProperties | - | |
| styles | 语义化结构 style | [Record<SemanticDOM, CSSProperties>](#semantic-dom) | - | 5.10.0 |
| title | 标题 | ReactNode | - | |
| loading | 显示旋转指示器 | boolean \| `Omit<SpinProp, 'fullScreen' \| 'tip'>` | false | 5.17.0 |
| open | Drawer 是否可见 | boolean | - |
| width | 宽度 | string \| number | 378 | |
| zIndex | 设置 Drawer 的 `z-index` | number | 1000 | |
Expand Down

0 comments on commit 6f6868f

Please sign in to comment.