Skip to content

Commit b24fe77

Browse files
authored
feat(popover): add popover component with scrollable content (#645)
1 parent 20f8d31 commit b24fe77

10 files changed

Lines changed: 193 additions & 0 deletions

File tree

‎src/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export { default as MarkdownRender } from './markdownRender';
3232
export { default as Modal } from './modal';
3333
export { default as NotFound } from './notFound';
3434
export { default as Popconfirm } from './popConfirm';
35+
export { default as Popover } from './popover';
3536
export { default as ProgressBar } from './progressBar';
3637
export { default as ProgressLine } from './progressLine';
3738
export { default as Resize } from './resize';
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import React from 'react';
2+
import { render, screen, waitFor } from '@testing-library/react';
3+
import '@testing-library/jest-dom/extend-expect';
4+
5+
import Popover from '..';
6+
7+
describe('Popover', () => {
8+
it('should render popover with default overlay className', async () => {
9+
render(
10+
<Popover title="Popover title" content="Popover content" visible>
11+
<span>Hover me</span>
12+
</Popover>
13+
);
14+
15+
await waitFor(() => expect(screen.getByText('Popover content')).toBeInTheDocument());
16+
17+
expect(document.querySelector('.dtc-popover')).toBeInTheDocument();
18+
});
19+
20+
it('should merge custom overlayClassName', async () => {
21+
render(
22+
<Popover
23+
title="Popover title"
24+
content="Popover content"
25+
overlayClassName="custom-popover"
26+
visible
27+
>
28+
<span>Hover me</span>
29+
</Popover>
30+
);
31+
32+
await waitFor(() => expect(document.querySelector('.dtc-popover')).toBeInTheDocument());
33+
34+
expect(document.querySelector('.dtc-popover')).toHaveClass('custom-popover');
35+
});
36+
37+
it('should pass overlayInnerStyle to antd Popover', async () => {
38+
render(
39+
<Popover
40+
title="Popover title"
41+
content="Popover content"
42+
overlayInnerStyle={{ color: 'red' }}
43+
visible
44+
>
45+
<span>Hover me</span>
46+
</Popover>
47+
);
48+
49+
await waitFor(() =>
50+
expect(document.querySelector('.ant-popover-inner')).toBeInTheDocument()
51+
);
52+
53+
expect(document.querySelector('.ant-popover-inner')).toHaveStyle({
54+
color: 'red',
55+
});
56+
});
57+
});

‎src/popover/demos/basic.tsx‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from 'react';
2+
import { Button } from 'antd';
3+
import { Popover } from 'dt-react-component';
4+
5+
export default function Basic() {
6+
return (
7+
<Popover title="标题" content="这是一段 Popover 内容">
8+
<Button type="primary">Hover me</Button>
9+
</Popover>
10+
);
11+
}

‎src/popover/demos/customHeight.tsx‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React, { CSSProperties } from 'react';
2+
import { Button } from 'antd';
3+
import { Popover } from 'dt-react-component';
4+
5+
const content = Array.from({ length: 12 }, (_, index) => (
6+
<div key={index}>这是第 {index + 1} 行自定义高度的 Popover 内容</div>
7+
));
8+
9+
export default function CustomHeight() {
10+
return (
11+
<Popover
12+
title="自定义高度"
13+
content={<div>{content}</div>}
14+
trigger="click"
15+
overlayStyle={{ '--max-height': '160px' } as CSSProperties}
16+
>
17+
<Button>点击查看自定义高度 Popover</Button>
18+
</Popover>
19+
);
20+
}

‎src/popover/demos/maxWidth.tsx‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from 'react';
2+
import { Button } from 'antd';
3+
import { Popover } from 'dt-react-component';
4+
5+
export default function MaxWidth() {
6+
return (
7+
<Popover
8+
title="最大宽度"
9+
content="这是一段非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常长的 Popover 内容,用于展示浮层最大宽度为 400px 时的换行效果。"
10+
>
11+
<Button>最大宽度 Popover</Button>
12+
</Popover>
13+
);
14+
}

‎src/popover/demos/noTitle.tsx‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from 'react';
2+
import { Button } from 'antd';
3+
import { Popover } from 'dt-react-component';
4+
5+
export default function NoTitle() {
6+
return (
7+
<Popover content="这是一段没有标题的 Popover 内容">
8+
<Button>无标题 Popover</Button>
9+
</Popover>
10+
);
11+
}

‎src/popover/demos/scroll.tsx‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React from 'react';
2+
import { Button } from 'antd';
3+
import { Popover } from 'dt-react-component';
4+
5+
const content = Array.from({ length: 30 }, (_, index) => (
6+
<div key={index}>这是第 {index + 1} 行较长的 Popover 内容</div>
7+
));
8+
9+
export default function Scroll() {
10+
return (
11+
<Popover title="长内容" content={<div>{content}</div>} trigger="click">
12+
<Button>点击查看长内容 Popover</Button>
13+
</Popover>
14+
);
15+
}

‎src/popover/index.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
title: Popover 气泡卡片
3+
group: 组件
4+
toc: content
5+
demo:
6+
cols: 2
7+
---
8+
9+
# Popover 气泡卡片
10+
11+
## 何时使用
12+
13+
用于展示更丰富的气泡内容。组件基于 antd Popover 封装,浮层内容最大高度为 400px,超过后可滚动查看。
14+
15+
## 代码演示
16+
17+
<code src="./demos/basic.tsx" title="基本使用" description="Popover 的基本使用。"></code>
18+
<code src="./demos/noTitle.tsx" title="无标题内容" description="仅展示内容的 Popover。"></code>
19+
<code src="./demos/scroll.tsx" title="长内容滚动" description="当 Popover 内容超过 400px 时,浮层内部滚动。"></code>
20+
<code src="./demos/customHeight.tsx" title="自定义高度" description="通过 CSS 变量自定义 Popover 浮层内容最大高度。"></code>
21+
<code src="./demos/maxWidth.tsx" title="最大宽度" description="Popover 浮层最大宽度为 400px,长内容自动换行。"></code>
22+
23+
## API
24+
25+
### Popover
26+
27+
Popover 组件支持 antd Popover 组件的所有属性,详见 [Ant Design Popover API](https://ant.design/components/popover-cn/#API)。

‎src/popover/index.scss‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
.dtc-popover {
2+
min-width: 220px;
3+
max-width: 400px;
4+
.ant-popover-inner {
5+
border-radius: 4px;
6+
}
7+
.ant-popover-title {
8+
padding: 16px 16px 0;
9+
border-bottom: 0;
10+
font-weight: 500;
11+
font-size: 14px;
12+
color: #3D446E;
13+
}
14+
.ant-popover-inner-content {
15+
padding: 16px;
16+
max-height: var(--max-height, 400px);
17+
overflow-y: auto;
18+
font-size: 12px;
19+
color: #8B8FA8;
20+
}
21+
.ant-popover-title + .ant-popover-inner-content {
22+
padding-top: 4px;
23+
}
24+
}

‎src/popover/index.tsx‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React from 'react';
2+
import { Popover as AntdPopover, PopoverProps as AntdPopoverProps } from 'antd';
3+
import classNames from 'classnames';
4+
5+
import './index.scss';
6+
7+
export type PopoverProps = AntdPopoverProps;
8+
9+
const Popover = ({ overlayClassName, ...rest }: PopoverProps) => {
10+
return <AntdPopover overlayClassName={classNames('dtc-popover', overlayClassName)} {...rest} />;
11+
};
12+
13+
export default Popover;

0 commit comments

Comments
 (0)