Skip to content

Commit c533549

Browse files
authoredApr 6, 2022
fix(Overlay/Modal): 新增 Modal.show() 快速使用弹框功能,修复Overlay首次打开没有动画问题 (#746)
1 parent 1358ef5 commit c533549

File tree

4 files changed

+166
-100
lines changed

4 files changed

+166
-100
lines changed
 

‎packages/react-modal/README.md

+34
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,35 @@ class Demo extends React.Component {
323323
ReactDOM.render(<Demo />, _mount_);
324324
```
325325

326+
### 快捷弹出
327+
328+
使用 show() 可以快捷地弹出确认框。接受的参数与 ModalProps 一样, 只是少了 isOpen 与 onClosed
329+
330+
<!--rehype:bgWhite=true&codeSandbox=true&codePen=true-->
331+
```jsx
332+
import React from 'react';
333+
import ReactDOM from 'react-dom';
334+
import { Modal, ButtonGroup, Button } from 'uiw';
335+
336+
class Demo extends React.Component {
337+
onClick() {
338+
Modal.show({
339+
confirmText: "知道了",
340+
children: "快捷提示",
341+
onConfirm: () => console.log('您点击了确定按钮!'),
342+
})
343+
}
344+
render() {
345+
return (
346+
<div>
347+
<Button onClick={this.onClick.bind(this)}>确认对话框</Button>
348+
</div>
349+
)
350+
}
351+
}
352+
ReactDOM.render(<Demo />, _mount_);
353+
```
354+
326355
## Props
327356

328357
| 参数 | 说明 | 类型 | 默认值 |
@@ -345,4 +374,9 @@ ReactDOM.render(<Demo />, _mount_);
345374
| isOpen[`<Overlay>`](#/components/overlay) | 对话框是否可见 | Boolean | `false` |
346375
| maskClosable[`<Overlay>`](#/components/overlay) | 点击遮罩层是否允许关闭 | Boolean | `true` |
347376

377+
## Modal.show(params)
378+
379+
params: Omit<ModalProps, \'onClosed\' \| \'isOpen\'> & { children: React.ReactNode }
380+
381+
348382
更多属性文档请参考 [Overlay](#/components/overlay)

‎packages/react-modal/src/CallShow.tsx

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
import Modal, { ModalProps } from './';
4+
5+
export default function CallShow(props: Omit<ModalProps, 'onClosed' | 'isOpen'> & { children: React.ReactNode }) {
6+
const { title = '提示框', children, ...other } = props;
7+
const dv = document.createElement('div');
8+
dv.id = 'uiw-modal-call-show-element';
9+
document.body.appendChild(dv);
10+
ReactDOM.render(
11+
<Modal
12+
{...other}
13+
title={title}
14+
isOpen={true}
15+
onClosed={() => {
16+
document.getElementById('uiw-modal-call-show-element')!.remove();
17+
}}
18+
>
19+
{children}
20+
</Modal>,
21+
document.getElementById('uiw-modal-call-show-element'),
22+
);
23+
}

‎packages/react-modal/src/index.tsx

+107-98
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Button, { ButtonType, ButtonProps } from '@uiw/react-button';
44
import Icon, { IconProps } from '@uiw/react-icon';
55
import { IProps, noop } from '@uiw/utils';
66
import './style/index.less';
7+
import CallShow from './CallShow';
78

89
export interface ModalProps extends IProps, OverlayProps {
910
type?: ButtonType;
@@ -27,105 +28,113 @@ export interface ModalProps extends IProps, OverlayProps {
2728
onConfirm?: (evn: React.MouseEvent<HTMLButtonElement> & MouseEvent) => void;
2829
}
2930

30-
export default React.forwardRef<OverlayProps, ModalProps>((props, ref) => {
31-
const {
32-
prefixCls = 'w-modal',
33-
className,
34-
children,
35-
useButton = true,
36-
usePortal = true,
37-
autoFocus = false,
38-
isOpen: _ = false,
39-
title,
40-
cancelText,
41-
cancelButtonProps,
42-
confirmButtonProps,
43-
content,
44-
confirmText = '确认',
45-
type = 'light',
46-
icon,
47-
maxWidth = 500,
48-
minWidth = 320,
49-
width,
50-
isCloseButtonShown = true,
51-
onCancel = noop,
52-
onConfirm = noop,
53-
bodyStyle,
54-
...other
55-
} = props;
56-
const [isOpen, setIsOpen] = useState(props.isOpen);
57-
useEffect(() => {
58-
if (props.isOpen !== isOpen) {
59-
setIsOpen(props.isOpen);
60-
}
61-
}, [props.isOpen]);
31+
type ShowModalProps = {
32+
show?: (props: Omit<ModalProps, 'onClosed' | 'isOpen'> & { children: React.ReactNode }) => void;
33+
};
34+
35+
const Modal: React.ForwardRefExoticComponent<ModalProps & React.RefAttributes<OverlayProps>> & ShowModalProps =
36+
React.forwardRef<OverlayProps, ModalProps>((props, ref) => {
37+
const {
38+
prefixCls = 'w-modal',
39+
className,
40+
children,
41+
useButton = true,
42+
usePortal = true,
43+
autoFocus = false,
44+
isOpen: _ = false,
45+
title,
46+
cancelText,
47+
cancelButtonProps,
48+
confirmButtonProps,
49+
content,
50+
confirmText = '确认',
51+
type = 'light',
52+
icon,
53+
maxWidth = 500,
54+
minWidth = 320,
55+
width,
56+
isCloseButtonShown = true,
57+
onCancel = noop,
58+
onConfirm = noop,
59+
bodyStyle,
60+
...other
61+
} = props;
62+
const [isOpen, setIsOpen] = useState(props.isOpen);
63+
useEffect(() => {
64+
if (props.isOpen !== isOpen) {
65+
setIsOpen(props.isOpen);
66+
}
67+
}, [props.isOpen]);
6268

63-
const [loading, setLoading] = useState(false);
64-
const cls = [prefixCls, className, type ? `${type}` : null].filter(Boolean).join(' ').trim();
65-
function onClose() {
66-
setIsOpen(false);
67-
}
68-
async function handleCancel(e: React.MouseEvent<HTMLButtonElement, MouseEvent> & MouseEvent) {
69-
setLoading(true);
70-
try {
71-
onCancel && (await onCancel(e));
72-
} catch (e) {}
73-
setIsOpen(false);
74-
setLoading(false);
75-
}
76-
async function handleConfirm(e: React.MouseEvent<HTMLButtonElement, MouseEvent> & MouseEvent) {
77-
setLoading(true);
78-
try {
79-
onConfirm && (await onConfirm(e));
80-
} catch (e) {}
81-
setIsOpen(false);
82-
setLoading(false);
83-
}
84-
return (
85-
<Overlay usePortal={usePortal} isOpen={isOpen} {...other} onClose={onClose} className={cls}>
86-
<div className={`${prefixCls}-container`}>
87-
<div
88-
className={[
89-
`${prefixCls}-inner`,
90-
title ? `${prefixCls}-shown-title` : null,
91-
icon ? `${prefixCls}-shown-icon` : null,
92-
]
93-
.filter(Boolean)
94-
.join(' ')
95-
.trim()}
96-
style={{ maxWidth, minWidth, width }}
97-
>
98-
{(title || icon) && (
99-
<div className={`${prefixCls}-header`}>
100-
{icon && <Icon type={icon} />}
101-
{title && <h4>{title}</h4>}
102-
{isCloseButtonShown && <Button basic onClick={(e) => handleCancel(e)} icon="close" type="light" />}
69+
const [loading, setLoading] = useState(false);
70+
const cls = [prefixCls, className, type ? `${type}` : null].filter(Boolean).join(' ').trim();
71+
function onClose() {
72+
setIsOpen(false);
73+
}
74+
async function handleCancel(e: React.MouseEvent<HTMLButtonElement, MouseEvent> & MouseEvent) {
75+
setLoading(true);
76+
try {
77+
onCancel && (await onCancel(e));
78+
} catch (e) {}
79+
setIsOpen(false);
80+
setLoading(false);
81+
}
82+
async function handleConfirm(e: React.MouseEvent<HTMLButtonElement, MouseEvent> & MouseEvent) {
83+
setLoading(true);
84+
try {
85+
onConfirm && (await onConfirm(e));
86+
} catch (e) {}
87+
setIsOpen(false);
88+
setLoading(false);
89+
}
90+
return (
91+
<Overlay usePortal={usePortal} isOpen={isOpen} {...other} onClose={onClose} className={cls}>
92+
<div className={`${prefixCls}-container`}>
93+
<div
94+
className={[
95+
`${prefixCls}-inner`,
96+
title ? `${prefixCls}-shown-title` : null,
97+
icon ? `${prefixCls}-shown-icon` : null,
98+
]
99+
.filter(Boolean)
100+
.join(' ')
101+
.trim()}
102+
style={{ maxWidth, minWidth, width }}
103+
>
104+
{(title || icon) && (
105+
<div className={`${prefixCls}-header`}>
106+
{icon && <Icon type={icon} />}
107+
{title && <h4>{title}</h4>}
108+
{isCloseButtonShown && <Button basic onClick={(e) => handleCancel(e)} icon="close" type="light" />}
109+
</div>
110+
)}
111+
<div className={`${prefixCls}-body`} style={bodyStyle}>
112+
{children || content}
103113
</div>
104-
)}
105-
<div className={`${prefixCls}-body`} style={bodyStyle}>
106-
{children || content}
107-
</div>
108-
{useButton && (
109-
<div className={`${prefixCls}-footer`}>
110-
<Button
111-
autoFocus={autoFocus}
112-
type={type}
113-
loading={loading}
114-
disabled={loading}
115-
{...confirmButtonProps}
116-
onClick={(e) => handleConfirm(e)}
117-
>
118-
{confirmText}
119-
</Button>
120-
{cancelText && (
121-
<Button {...cancelButtonProps} onClick={(e) => handleCancel(e)}>
122-
{cancelText}
114+
{useButton && (
115+
<div className={`${prefixCls}-footer`}>
116+
<Button
117+
autoFocus={autoFocus}
118+
type={type}
119+
loading={loading}
120+
disabled={loading}
121+
{...confirmButtonProps}
122+
onClick={(e) => handleConfirm(e)}
123+
>
124+
{confirmText}
123125
</Button>
124-
)}
125-
</div>
126-
)}
126+
{cancelText && (
127+
<Button {...cancelButtonProps} onClick={(e) => handleCancel(e)}>
128+
{cancelText}
129+
</Button>
130+
)}
131+
</div>
132+
)}
133+
</div>
127134
</div>
128-
</div>
129-
</Overlay>
130-
);
131-
});
135+
</Overlay>
136+
);
137+
});
138+
139+
Modal.show = CallShow;
140+
export default Modal;

‎packages/react-overlay/src/index.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ export default function Overlay(props: OverlayProps) {
6161
...otherProps
6262
} = props;
6363

64-
const [isOpen, setIsOpen] = useState(props.isOpen || false);
64+
const [isOpen, setIsOpen] = useState<boolean>();
65+
// const [isOpen, setIsOpen] = useState(props.isOpen || false);
6566
const [visible, setVisible] = useState(false);
6667
const container = useRef<HTMLDivElement>(null);
6768
const overlay = useRef<HTMLDivElement>(null);
@@ -127,7 +128,6 @@ export default function Overlay(props: OverlayProps) {
127128
// setVisible(false)
128129
// }
129130
}
130-
131131
const TransitionGroupComp = (
132132
<CSSTransition
133133
classNames={transitionName}

0 commit comments

Comments
 (0)
Please sign in to comment.