Skip to content
Open
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
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export { default as KeyEventListener } from './keyEventListener';
export { default as MarkdownRender } from './markdownRender';
export { default as Modal } from './modal/modal';
export { default as NotFound } from './notFound';
export { default as Popconfirm } from './popConfirm';
export { default as ProgressBar } from './progressBar';
export { default as ProgressLine } from './progressLine';
export { default as Resize } from './resize';
Expand Down
62 changes: 62 additions & 0 deletions src/popConfirm/__tests__/__snapshots__/index.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Popconfirm should render Popconfirm success render 1`] = `
<div
class="ant-popover ant-popconfirm dtc-popconfirm"
style="opacity: 0;"
>
<div
class="ant-popover-content"
>
<div
class="ant-popover-arrow"
>
<span
class="ant-popover-arrow-content"
/>
</div>
<div
class="ant-popover-inner"
role="tooltip"
>
<div
class="ant-popover-inner-content"
>
<div
class="ant-popover-message"
>
<span
color="#1D78FF"
data-mock-icon="InformationFilled"
/>
<div
class="ant-popover-message-title"
>
Are you sure?
</div>
</div>
<div
class="ant-popover-buttons"
>
<button
class="ant-btn ant-btn-default ant-btn-sm"
type="button"
>
<span>
Cancel
</span>
</button>
<button
class="ant-btn ant-btn-primary ant-btn-sm"
type="button"
>
<span>
OK
</span>
</button>
</div>
</div>
</div>
</div>
</div>
`;
121 changes: 121 additions & 0 deletions src/popConfirm/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import React from 'react';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';

import Popconfirm from '../index';

describe('Popconfirm', () => {
test('should render Popconfirm success render', async () => {
render(<Popconfirm title="Are you sure?">Click me</Popconfirm>);
fireEvent.click(screen.getByText('Click me'));
expect(screen.getByText('Are you sure?')).toBeInTheDocument();
await waitFor(() =>
expect(document.querySelector('.ant-popover-message')?.firstChild).toHaveAttribute(
'data-mock-icon',
'InformationFilled'
)
);
await waitFor(() => expect(document.querySelector('.ant-popover')).toMatchSnapshot());
await waitFor(() => expect(document.querySelector('.dtc-popconfirm')).toBeInTheDocument());
});

it('should show overlay when trigger is clicked', async () => {
const popconfirm = render(
<Popconfirm title="code" trigger="click" autoAdjustOverflow={false}>
<span>show me your code</span>
</Popconfirm>
);

expect(popconfirm.container.querySelector('.ant-popover')).toBe(null);

const triggerNode = popconfirm.container.querySelectorAll('span')[0];
fireEvent.click(triggerNode);

await waitFor(() => expect(document.querySelector('.ant-popover')).not.toBeNull());
});

it('should render correctly with warning type and warning icon', async () => {
render(
<Popconfirm title="Warning!" type="warning">
Click me
</Popconfirm>
);
fireEvent.click(screen.getByText('Click me'));
await waitFor(() => expect(screen.getByText('Warning!')).toBeInTheDocument());
await waitFor(() =>
expect(document.querySelector('.ant-popover-message')?.firstChild).toHaveAttribute(
'data-mock-icon',
'WarningFilled'
)
);
});

it('should render correctly with danger type and close icon', async () => {
render(
<Popconfirm title="Danger!" type="danger">
Click me
</Popconfirm>
);
fireEvent.click(screen.getByText('Click me'));
await waitFor(() => expect(screen.getByText('Danger!')).toBeInTheDocument());
});

it('should not render icon when showIcon is false', async () => {
render(
<Popconfirm title="No Icon" showIcon={false}>
Click me
</Popconfirm>
);
fireEvent.click(screen.getByText('Click me'));
await waitFor(() => expect(screen.getByText('No Icon')).toBeInTheDocument());
await waitFor(() =>
expect(document.querySelector('.ant-popover-message')?.children.length).toBe(1)
);
});

it('should use custom icon when provided', async () => {
const CustomIcon = () => <div data-testid="custom-icon">Custom</div>;
render(
<Popconfirm title="Custom Icon" icon={<CustomIcon />}>
Click me
</Popconfirm>
);
fireEvent.click(screen.getByText('Click me'));
await waitFor(() => expect(screen.getByTestId('custom-icon')).toBeInTheDocument());
});

it('should trigger onConfirm when OK button is clicked', async () => {
const onConfirm = jest.fn();
render(
<Popconfirm title="Confirm?" onConfirm={onConfirm}>
Click me
</Popconfirm>
);
fireEvent.click(screen.getByText('Click me'));
fireEvent.click(await screen.findByText('OK'));
expect(onConfirm).toHaveBeenCalled();
});

it('should trigger onCancel when Cancel button is clicked', async () => {
const onCancel = jest.fn();
render(
<Popconfirm title="Cancel?" onCancel={onCancel}>
Click me
</Popconfirm>
);
fireEvent.click(screen.getByText('Click me'));
fireEvent.click(await screen.findByText('Cancel'));
expect(onCancel).toHaveBeenCalled();
});

it('should apply danger style to OK button for danger type', async () => {
render(
<Popconfirm title="Danger!" type="danger">
Click me
</Popconfirm>
);
fireEvent.click(screen.getByText('Click me'));
const okButton = await screen.findByText('OK');
expect(okButton.closest('button')).toHaveClass('ant-btn-dangerous');
});
});
19 changes: 19 additions & 0 deletions src/popConfirm/demos/basic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { Space } from 'antd';
import { Popconfirm } from 'dt-react-component';

const App: React.FC = () => (
<Space size={12}>
<Popconfirm title="Are you sure to delete this task?">
<a href="#">Basic</a>
</Popconfirm>
<Popconfirm
title="超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本超长文本"
overlayInnerStyle={{ width: 400 }}
>
<a href="#">超长文本</a>
</Popconfirm>
</Space>
);

export default App;
15 changes: 15 additions & 0 deletions src/popConfirm/demos/noIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import { PlusCircleFilled } from '@dtinsight/react-icons';
import { Space } from 'antd';
import { Button, Popconfirm } from 'dt-react-component';

export default () => (
<Space>
<Popconfirm title="没有图标" showIcon={false}>
<Button>无图标确认</Button>
</Popconfirm>
<Popconfirm title="警告操作" icon={<PlusCircleFilled />}>
<Button type="default">自定义icon</Button>
</Popconfirm>
</Space>
);
17 changes: 17 additions & 0 deletions src/popConfirm/demos/type.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import { Space } from 'antd';
import { Button, Popconfirm } from 'dt-react-component';

export default () => (
<Space>
<Popconfirm title="主操作" type="primary">
<Button type="primary">主操作</Button>
</Popconfirm>
<Popconfirm title="警告操作" type="warning">
<Button type="default">警告</Button>
</Popconfirm>
<Popconfirm title="危险操作" type="danger">
<Button danger>危险</Button>
</Popconfirm>
</Space>
);
24 changes: 24 additions & 0 deletions src/popConfirm/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
title: Popconfirm 气泡确认框
group: 组件
toc: content
---

# Popconfirm 气泡确认框

对操作进行二次确认,支持自定义图标和类型。

## 示例

<code src="./demos/basic.tsx" title="基础"></code>
<code src="./demos/type.tsx" title="类型"></code>
<code src="./demos/noIcon.tsx" title="没有图标"></code>

## API

| 属性 | 说明 | 类型 | 默认值 |
| -------- | ------------ | ---------------------------------- | --------- |
| showIcon | 是否显示图标 | boolean | true |
| type | 图标类型 | 'primary' \| 'warning' \| 'danger' | 'primary' |

其余属性均继承自 `Popconfirm` 组件,参考 [Popconfirm API](https://4x.ant.design/components/popconfirm-cn/#API)
13 changes: 13 additions & 0 deletions src/popConfirm/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.dtc-popconfirm {
.ant-popover-message {
display: flex;
align-items: start;
&-title {
padding-left: 0;
}
}
.dtstack-icon {
margin-right: 8px;
font-size: 20px;
}
}
45 changes: 45 additions & 0 deletions src/popConfirm/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import { CloseFilled, InformationFilled, WarningFilled } from '@dtinsight/react-icons';
import { Popconfirm as AntdPopconfirm, PopconfirmProps as AntdPopconfirmProps } from 'antd';
import classNames from 'classnames';

import './index.scss';

export interface PopconfirmProps extends AntdPopconfirmProps {
showIcon?: boolean;
type?: 'primary' | 'warning' | 'danger';
}

const Popconfirm = ({
showIcon = true,
type = 'primary',
icon,
okButtonProps,
...rest
}: PopconfirmProps) => {
const generateIcon = () => {
if (!showIcon) return <></>;
if (icon) return icon;
switch (type) {
case 'primary':
return <InformationFilled color="#1D78FF" />;
case 'warning':
return <WarningFilled color="#FBB310" />;
case 'danger':
return <CloseFilled color="#F96C5B" />;
default:
return <></>;
}
};

return (
<AntdPopconfirm
overlayClassName={classNames('dtc-popconfirm')}
icon={generateIcon()}
okButtonProps={{ danger: type === 'danger', ...okButtonProps }}
{...rest}
/>
);
};

export default Popconfirm;
Loading