Skip to content

Commit

Permalink
feat(Confirm): add confirm component (#1409)
Browse files Browse the repository at this point in the history
* feat(Confirm): add confirm component

* docs(PopConfirm): show popconfirm with/without desc

Co-authored-by: Zhang Rui <zhangrui@growingio.com>
  • Loading branch information
Ryan Zhang and Zhang Rui authored Nov 2, 2021
1 parent 74a0d9e commit 3dfb19c
Show file tree
Hide file tree
Showing 10 changed files with 423 additions and 2 deletions.
91 changes: 91 additions & 0 deletions src/popconfirm/PopConfirm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React, { useCallback, useEffect, useState } from 'react';
import { WarningCircleFilled } from '@gio-design/icons';
import { isUndefined } from 'lodash';
import usePrefixCls from '../utils/hooks/use-prefix-cls';
import Button from '../button';
import Popover from '../popover/Popover';
import { PopConfirmProps } from './interface';

const PopConfirm: React.FC<PopConfirmProps> = (props) => {
const {
prefixCls: customizePrefixCls,
title,
desc,
onCancel: onCustomizeCancel,
onConfirm: onCustomizeConfirm,
onVisibleChange: onCustomizeVisibleChange,
okText,
cancelText,
icon,
visible: customizaVisible,
children,
disabled,
...rest
} = props;
const prefixCls = usePrefixCls('confirm-new', customizePrefixCls);

const [visible, setVisible] = useState(customizaVisible);

const onVisibleChange = useCallback(
(resetVisible: boolean) => {
const realVisible = !disabled && resetVisible;
setVisible(realVisible);
onCustomizeVisibleChange?.(realVisible);
},
[disabled, onCustomizeVisibleChange]
);

const onCancel = useCallback(
(e) => {
setVisible(false);
onCustomizeCancel?.(e);
onCustomizeVisibleChange?.(false);
},
[onCustomizeCancel, onCustomizeVisibleChange]
);
const onConfirm = useCallback(
(e) => {
const confirmCode = onCustomizeConfirm?.(e);
if (confirmCode !== false) {
setVisible(false);
onCustomizeVisibleChange?.(false);
}
},
[onCustomizeConfirm, onCustomizeVisibleChange]
);

useEffect(() => {
if (!isUndefined(customizaVisible)) {
setVisible(customizaVisible);
}
}, [customizaVisible]);

const content = (
<div className={`${prefixCls}`}>
<div className={`${prefixCls}__content`}>
<div className={`${prefixCls}__content-title`}>
{icon || <WarningCircleFilled />}
<span className={`${prefixCls}__content-title-text`}>{title}</span>
</div>
{desc && <div className={`${prefixCls}__content-desc`}>{desc}</div>}
</div>
<div className={`${prefixCls}__footer`}>
<div>
<Button onClick={onCancel} size="small" type="secondary">
{cancelText || '取消'}
</Button>
<Button onClick={onConfirm} size="small">
{okText || '确认'}
</Button>
</div>
</div>
</div>
);
return (
<Popover {...rest} visible={visible} enterable onVisibleChange={onVisibleChange} content={content}>
{children}
</Popover>
);
};

export default PopConfirm;
237 changes: 237 additions & 0 deletions src/popconfirm/demos/PopConfirm.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
import React, { useState } from 'react';
import { Story, Meta } from '@storybook/react/types-6-0';
import { withDesign } from 'storybook-addon-designs';
import PopConfirm from '../PopConfirm';
import { PopConfirmProps } from '../interface';
import Input from '../../input';
import { Button } from '../../button';
import '../style';
import '../../popover/demos/demo.stories.less';

export default {
title: 'Upgraded/PopConfirm',
component: PopConfirm,
decorators: [withDesign],
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/lLYusioN7e9ifkQnIXeT4G/GIO-Design-(Running-File)?node-id=6392%3A67234',
allowFullscreen: true,
},
docs: {
page: null,
},
},
} as Meta;

const Template: Story<PopConfirmProps> = (args) => (
<div style={{ display: 'flex', alignItems: 'center', width: '1500px' }}>
<div style={{ margin: '200px 300px' }}>
<div className="tooltip-top">
<span className="popover-wrapper">
<PopConfirm {...args} placement="topLeft">
<span className="popover-span">TopLeft</span>
</PopConfirm>
</span>
<span className="popover-wrapper">
<PopConfirm {...args} placement="top">
<span className="popover-span">Top</span>
</PopConfirm>
</span>
<span className="popover-wrapper">
<PopConfirm {...args} placement="topRight">
<span className="popover-span">TopRight</span>
</PopConfirm>
</span>
</div>
<div className="tooltip-left" style={{ marginLeft: '40px' }}>
<span className="popover-wrapper">
<PopConfirm {...args} placement="leftTop">
<span className="popover-span">LeftTop</span>
</PopConfirm>
</span>
<span className="popover-wrapper">
<PopConfirm {...args} placement="left">
<span className="popover-span">Left</span>
</PopConfirm>
</span>
<span className="popover-wrapper">
<PopConfirm {...args} placement="leftBottom">
<span className="popover-span">LeftBottom</span>
</PopConfirm>
</span>
</div>
<div className="tooltip-right" style={{ marginLeft: '455px' }}>
<span className="popover-wrapper">
<PopConfirm {...args} placement="rightTop">
<span className="popover-span">RightTop</span>
</PopConfirm>
</span>
<span className="popover-wrapper">
<PopConfirm {...args} placement="right">
<span className="popover-span">Right</span>
</PopConfirm>
</span>
<span className="popover-wrapper">
<PopConfirm {...args} placement="rightBottom">
<span className="popover-span">RightBottom</span>
</PopConfirm>
</span>
</div>
<div className="tooltip-buttom">
<span className="popover-wrapper">
<PopConfirm {...args} placement="bottomLeft">
<span className="popover-span">BottomLeft</span>
</PopConfirm>
</span>
<span className="popover-wrapper">
<PopConfirm {...args} placement="bottom">
<span className="popover-span">Bottom</span>
</PopConfirm>
</span>
<span className="popover-wrapper">
<PopConfirm {...args} placement="bottomRight">
<span className="popover-span">BottomRight</span>
</PopConfirm>
</span>
</div>
</div>
</div>
);
const content = {
title: '确定要删除……吗?',
desc: '删除物品属性后,相关数据将停止计算,历史数据将会被保留。',
};
export const Placement = Template.bind({});
Placement.args = {
arrowPointAtCenter: true,
...content,
};

const TriggerTemplate: Story<PopConfirmProps> = (args) => (
<div style={{ margin: '200px 200px' }}>
<span style={{ marginRight: 20 }}>
<PopConfirm {...args} trigger="hover" placement="top">
<Input value="Touch Me!" style={{ width: 100 }} />
</PopConfirm>
</span>
<span style={{ marginRight: 20 }}>
<PopConfirm {...args} trigger="focus" placement="top">
<Input value="Focus Me!" style={{ width: 100 }} />
</PopConfirm>
</span>
<span style={{ marginRight: 20 }}>
<PopConfirm {...args} trigger={['focus', 'click']} placement="top">
<Input value="Focus or Click Me!" style={{ width: 150 }} />
</PopConfirm>
</span>
<span style={{ marginRight: 20 }}>
<PopConfirm {...args} trigger="click" placement="top">
<Input value="Click Me!" style={{ width: 100 }} />
</PopConfirm>
</span>
</div>
);

export const Trigger = TriggerTemplate.bind({});
Trigger.args = {
...content,
};

const ControlTemplate: Story<PopConfirmProps> = (args) => {
const [visible, setVisible] = useState(false);
const show = () => setVisible(true);
const hide = () => setVisible(false);
const onVisibleChange = (resetVisible: boolean) => {
console.log(resetVisible);
};

const [visible2, setVisible2] = useState(false);
const show2 = () => setVisible2(true);
const hide2 = () => setVisible2(false);
const onVisibleChange2 = (resetVisible: boolean) => {
setVisible2(resetVisible);
};
return (
<>
<fieldset style={{ border: '1px solid var(--gray-2, #dfe4ee)', marginBottom: 100, padding: '50px 20px' }}>
<legend>Controlled</legend>
<div style={{ marginRight: 20 }}>
<Button onClick={show} style={{ marginRight: 10 }}>
Show Confirm
</Button>
<Button onClick={hide} style={{ marginRight: 50 }}>
Hide Confirm
</Button>
<PopConfirm {...args} visible={visible} placement="top" onVisibleChange={onVisibleChange}>
<Input value="Show Confirm Me!" />
</PopConfirm>
</div>
</fieldset>
<fieldset style={{ border: '1px solid var(--gray-2, #dfe4ee)', padding: '50px 20px' }}>
<legend>Controlled by onVisibleChange</legend>
<div style={{ marginRight: 20 }}>
<Button onClick={show2} style={{ marginRight: 10 }}>
Show Confirm
</Button>
<Button onClick={hide2} style={{ marginRight: 50 }}>
Hide Confirm
</Button>
<PopConfirm {...args} visible={visible2} placement="top" onVisibleChange={onVisibleChange2}>
<Input value="Show Confirm Me!" />
</PopConfirm>
</div>
</fieldset>
</>
);
};

export const Controlled = ControlTemplate.bind({});
Controlled.args = { ...content };

const DescTemplate: Story<PopConfirmProps> = (args) => (
<>
<PopConfirm {...args}>
<Input value="Show Confirm with desc" style={{ width: 280 }} />
</PopConfirm>
<span>|</span>
<PopConfirm {...args} desc="">
<Input value="Show Confirm without desc" style={{ width: 280 }} />
</PopConfirm>
</>
);
export const Description = DescTemplate.bind({});
Description.args = {
...content,
placement: 'topLeft',
};

// const DefaultTemplate: Story<PopConfirmProps> = (args) => (
// <>
// <PopConfirm {...args}>
// <Input value="Show Confirm with allowed Arrow" style={{ width: 280 }} />
// </PopConfirm>
// <span>|</span>
// <PopConfirm {...args} allowArrow={false}>
// <Input value="Show Confirm with rejected Arrow" style={{ width: 280 }} />
// </PopConfirm>
// </>
// );
// export const DefaultVisible = DefaultTemplate.bind({});
// DefaultVisible.args = {
// defaultVisible: true,
// ...content,
// };

const DisabledTemplate: Story<PopConfirmProps> = (args) => (
<>
<PopConfirm {...args}>
<Input value="Disabled PopConfirm" style={{ width: 280 }} />
</PopConfirm>
</>
);
export const Disabled = DisabledTemplate.bind({});
Disabled.args = {
disabled: true,
...content,
};
5 changes: 5 additions & 0 deletions src/popconfirm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import PopConfirm from './PopConfirm';
import { PopConfirmProps } from './interface';

export { PopConfirm, PopConfirmProps };
export default PopConfirm;
38 changes: 38 additions & 0 deletions src/popconfirm/interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { PopoverProps } from '../popover/interface';

export interface PopConfirmProps extends Omit<PopoverProps, 'title'> {
/**
确认框的主题
*/
title: string;
/**
确认框的描述
*/
desc?: string;
/**
点击取消的回调
*/
onCancel?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;
/**
点击确认的回调
*/
onConfirm?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => boolean | undefined;
/**
确认按钮文字
*/
okText?: string;
/**
取消按钮文字
*/
cancelText?: string;
/**
替换 title 前的 icon
*/
icon?: React.ReactNode;

/**
* 阻止点击 Popconfirm 子元素时弹出确认框
* @default false
*/
disabled?: boolean;
}
Loading

1 comment on commit 3dfb19c

@vercel
Copy link

@vercel vercel bot commented on 3dfb19c Nov 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.