Skip to content

Commit

Permalink
feat(components): 新增PopConfirm气泡确认框
Browse files Browse the repository at this point in the history
  • Loading branch information
mengxinssfd committed Jul 11, 2023
1 parent 7784e80 commit fd7e519
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 33 deletions.
102 changes: 80 additions & 22 deletions packages/components/src/pop-confirm/PopConfirm.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,98 @@
import React, { useMemo } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import type { PopConfirmProps } from './pop-confirm.types';
import { getComponentClass } from '@pkg/shared';
import type { RequiredPart } from '@tool-pack/types';
import { getClassNames } from '@tool-pack/basic';
import { getClassNames, isPromiseLike } from '@tool-pack/basic';
import { Tooltip } from '../tooltip';
import { Layout, Footer, Main, Header } from '../layouts';
import { Layout, Footer, Main } from '../layouts';
import { Button } from '../button';
import { Space } from '../space';
import { Icon } from '../icon';
import { CircleInfoFill } from '@pkg/icons';

const rootName = getComponentClass('pop-confirm');

export const PopConfirm: React.FC<PopConfirmProps> = (props) => {
const { header, onConfirm, onCancel, children, content, className, ...rest } =
props as RequiredPart<PopConfirmProps, keyof typeof defaultProps>;

const Content = useMemo(
() => (
<Layout vertical>
{header !== null && <Header>{header}</Header>}
<Main>{content}</Main>
<Footer>
<Space>
<Button type="info" size="small" onClick={onCancel}>
取消
const {
icon,
onConfirm,
confirmText,
onCancel,
cancelText,
children,
content,
className,
...rest
} = props as RequiredPart<PopConfirmProps, keyof typeof defaultProps>;

const [visible, setVisible] = useState<boolean | undefined>();

useEffect(() => {
visible !== undefined && setVisible(undefined);
}, [visible]);

const handleCallback = (
res: ReturnType<Required<PopConfirmProps>['onConfirm']>,
) => {
const hide = () => setVisible(false);

if (isPromiseLike(res)) {
res.then(hide).catch();
return;
}
if (res === undefined || res) hide();
};

const _onCancel = useCallback(() => {
handleCallback(onCancel?.());
}, [onCancel]);
const _onConfirm = useCallback(() => {
handleCallback(onConfirm?.());
}, [onConfirm]);

const Content = (
<Layout vertical>
<Main className={`${rootName}__main`}>
<Space>
{icon !== null &&
(icon || (
<Icon className={`${rootName}__icon`}>
<CircleInfoFill />
</Icon>
))}
{content}
</Space>
</Main>
<Footer className={`${rootName}__footer`}>
<Space>
{cancelText !== null && (
<Button
type="info"
plain
className={`${rootName}__cancel`}
size="small"
onClick={_onCancel}>
{cancelText}
</Button>
<Button type="primary" size="small" onClick={onConfirm}>
确认
)}
{confirmText !== null && (
<Button
type="primary"
className={`${rootName}__confirm`}
size="small"
onClick={_onConfirm}>
{confirmText}
</Button>
</Space>
</Footer>
</Layout>
),
[content, onConfirm, onCancel],
)}
</Space>
</Footer>
</Layout>
);

return (
<Tooltip
{...rest}
visible={visible}
className={getClassNames(rootName, className)}
title={Content}>
{children}
Expand All @@ -46,6 +102,8 @@ export const PopConfirm: React.FC<PopConfirmProps> = (props) => {

const defaultProps = {
trigger: 'click',
confirmText: '确认',
cancelText: '取消',
} satisfies Partial<PopConfirmProps>;
PopConfirm.defaultProps = defaultProps;
PopConfirm.displayName = 'PopConfirm';
27 changes: 27 additions & 0 deletions packages/components/src/pop-confirm/demo/callback.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* title: 事件回调
*/

import React from 'react';
import { Button, PopConfirm, useMessage } from '@tool-pack/react-ui';

const App: React.FC = () => {
const message = useMessage();
return (
<PopConfirm
content="确认要删除?"
onCancel={() => message.info('点击取消')}
onConfirm={() => {
message.info('确认删除,稍等...');
const p = new Promise<void>((resolve) => {
setTimeout(resolve, 1500);
});
p.then(() => message.success('删除成功!'));
return p;
}}>
<Button>删除</Button>
</PopConfirm>
);
};

export default App;
29 changes: 29 additions & 0 deletions packages/components/src/pop-confirm/demo/icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* title: icon
* description: 自定义 icon 或去除 icon。
*/

import React from 'react';
import { Button, Icon, Icons, PopConfirm, Space } from '@tool-pack/react-ui';

const App: React.FC = () => {
return (
<Space>
<PopConfirm
icon={
<Icon color="red">
<Icons.CircleWarningFill />
</Icon>
}
content="确认要删除?">
<Button>自定义图标</Button>
</PopConfirm>

<PopConfirm icon={null} content="确认要删除?">
<Button>无图标</Button>
</PopConfirm>
</Space>
);
};

export default App;
30 changes: 30 additions & 0 deletions packages/components/src/pop-confirm/demo/text.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* title: 按钮
* description: 自定义按钮文本或去除按钮。
*/

import React from 'react';
import { Button, PopConfirm, Space } from '@tool-pack/react-ui';

const App: React.FC = () => {
return (
<Space>
<PopConfirm
confirmText="confirm"
cancelText="cancel"
content="确认要删除?">
<Button>自定义文案</Button>
</PopConfirm>

<PopConfirm cancelText={null} content="确认要删除?">
<Button>只有确认</Button>
</PopConfirm>

<PopConfirm confirmText={null} content="确认要删除?">
<Button>只有取消</Button>
</PopConfirm>
</Space>
);
};

export default App;
14 changes: 13 additions & 1 deletion packages/components/src/pop-confirm/index.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
@import '../scss.variable';

$r: '#{$prefix}pop-confirm';
$space: '#{$prefix}space';

.#{$r} {}
.#{$r} {
width: 180px;
&__icon {
color: var(--t-color-warning);
}
&__footer {
margin-top: 12px;
.#{$space} {
justify-content: flex-end;
}
}
}
26 changes: 21 additions & 5 deletions packages/components/src/pop-confirm/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,35 @@ group:
title: 反馈
---

PopConfirm 说明
PopConfirm 气泡确认框

## 代码演示

<!-- prettier-ignore -->
<code src="./demo/basic.tsx"></code>
<code src="./demo/icon.tsx"></code>
<code src="./demo/text.tsx"></code>
<code src="./demo/callback.tsx"></code>

## API

PopConfirm 的属性说明如下:

| 属性 | 说明 | 类型 | 默认值 | 版本 |
| ---- | ---- | ---- | ------ | ---- |
| -- | -- | -- | -- | -- |
content?: React.ReactNode;
confirmText?: string | null;
onConfirm?: () => boolean | Promise<void> | void;
cancelText?: string | null;
onCancel?: () => boolean | Promise<void> | void;
icon?: React.ReactNode;

其他说明。
| 属性 | 说明 | 类型 | 默认值 | 版本 |
| ----------- | ----------------------------------------------------------------------------------------- | -------------------------------------- | ------- | ---- |
| content | 内容 | React.ReactNode | -- | -- |
| confirmText | 确认按钮文案,当值为 null 时,不显示确认按钮 | string \| null | '确认' | -- |
| onConfirm | 点击确认按钮时的回调,当回调返回值是 false 或者返回的 promise 的值是 false 则停止关闭窗体 | () => boolean \| Promise<void> \| void | -- | -- |
| cancelText | 取消按钮文案,当值为 null 时,不显示取消按钮 | string \| null | '取消' | -- |
| onCancel | 点击取消按钮时的回调,当回调返回值是 false 或者返回的 promise 的值是 false 则停止关闭窗体 | () => boolean \| Promise<void> \| void | -- | -- |
| icon | 自定义 icon,如果为 null 则不显示 icon | React.ReactNode | -- | -- |
| trigger |[tooltip](./tooltip#api) | -- | 'click' | -- |

更多说明见[tooltip](./tooltip#api)
11 changes: 6 additions & 5 deletions packages/components/src/pop-confirm/pop-confirm.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ export type PopConfirmProps = Omit<
React.HTMLAttributes<HTMLElement>,
'children'
> &
Pick<TooltipProps, 'placement' | 'trigger'> & {
header?: React.ReactNode;
TooltipProps & {
content?: React.ReactNode;
children: React.ReactElement;
onConfirm?: () => void;
onCancel?: () => void;
confirmText?: string | null;
onConfirm?: () => boolean | Promise<void> | void;
cancelText?: string | null;
onCancel?: () => boolean | Promise<void> | void;
icon?: React.ReactNode;
};

0 comments on commit fd7e519

Please sign in to comment.