Skip to content

Commit

Permalink
fix(Overlay/Modal): 新增 Modal.show() 快速使用弹框功能,修复Overlay首次打开没有动画问题 (#746)
Browse files Browse the repository at this point in the history
  • Loading branch information
cuilanxin committed Apr 6, 2022
1 parent 1358ef5 commit c533549
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 100 deletions.
34 changes: 34 additions & 0 deletions packages/react-modal/README.md
Expand Up @@ -323,6 +323,35 @@ class Demo extends React.Component {
ReactDOM.render(<Demo />, _mount_);
```

### 快捷弹出

使用 show() 可以快捷地弹出确认框。接受的参数与 ModalProps 一样, 只是少了 isOpen 与 onClosed

<!--rehype:bgWhite=true&codeSandbox=true&codePen=true-->
```jsx
import React from 'react';
import ReactDOM from 'react-dom';
import { Modal, ButtonGroup, Button } from 'uiw';

class Demo extends React.Component {
onClick() {
Modal.show({
confirmText: "知道了",
children: "快捷提示",
onConfirm: () => console.log('您点击了确定按钮!'),
})
}
render() {
return (
<div>
<Button onClick={this.onClick.bind(this)}>确认对话框</Button>
</div>
)
}
}
ReactDOM.render(<Demo />, _mount_);
```

## Props

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

## Modal.show(params)

params: Omit<ModalProps, \'onClosed\' \| \'isOpen\'> & { children: React.ReactNode }


更多属性文档请参考 [Overlay](#/components/overlay)
23 changes: 23 additions & 0 deletions packages/react-modal/src/CallShow.tsx
@@ -0,0 +1,23 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Modal, { ModalProps } from './';

export default function CallShow(props: Omit<ModalProps, 'onClosed' | 'isOpen'> & { children: React.ReactNode }) {
const { title = '提示框', children, ...other } = props;
const dv = document.createElement('div');
dv.id = 'uiw-modal-call-show-element';
document.body.appendChild(dv);
ReactDOM.render(
<Modal
{...other}
title={title}
isOpen={true}
onClosed={() => {
document.getElementById('uiw-modal-call-show-element')!.remove();
}}
>
{children}
</Modal>,
document.getElementById('uiw-modal-call-show-element'),
);
}
205 changes: 107 additions & 98 deletions packages/react-modal/src/index.tsx
Expand Up @@ -4,6 +4,7 @@ import Button, { ButtonType, ButtonProps } from '@uiw/react-button';
import Icon, { IconProps } from '@uiw/react-icon';
import { IProps, noop } from '@uiw/utils';
import './style/index.less';
import CallShow from './CallShow';

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

export default React.forwardRef<OverlayProps, ModalProps>((props, ref) => {
const {
prefixCls = 'w-modal',
className,
children,
useButton = true,
usePortal = true,
autoFocus = false,
isOpen: _ = false,
title,
cancelText,
cancelButtonProps,
confirmButtonProps,
content,
confirmText = '确认',
type = 'light',
icon,
maxWidth = 500,
minWidth = 320,
width,
isCloseButtonShown = true,
onCancel = noop,
onConfirm = noop,
bodyStyle,
...other
} = props;
const [isOpen, setIsOpen] = useState(props.isOpen);
useEffect(() => {
if (props.isOpen !== isOpen) {
setIsOpen(props.isOpen);
}
}, [props.isOpen]);
type ShowModalProps = {
show?: (props: Omit<ModalProps, 'onClosed' | 'isOpen'> & { children: React.ReactNode }) => void;
};

const Modal: React.ForwardRefExoticComponent<ModalProps & React.RefAttributes<OverlayProps>> & ShowModalProps =
React.forwardRef<OverlayProps, ModalProps>((props, ref) => {
const {
prefixCls = 'w-modal',
className,
children,
useButton = true,
usePortal = true,
autoFocus = false,
isOpen: _ = false,
title,
cancelText,
cancelButtonProps,
confirmButtonProps,
content,
confirmText = '确认',
type = 'light',
icon,
maxWidth = 500,
minWidth = 320,
width,
isCloseButtonShown = true,
onCancel = noop,
onConfirm = noop,
bodyStyle,
...other
} = props;
const [isOpen, setIsOpen] = useState(props.isOpen);
useEffect(() => {
if (props.isOpen !== isOpen) {
setIsOpen(props.isOpen);
}
}, [props.isOpen]);

const [loading, setLoading] = useState(false);
const cls = [prefixCls, className, type ? `${type}` : null].filter(Boolean).join(' ').trim();
function onClose() {
setIsOpen(false);
}
async function handleCancel(e: React.MouseEvent<HTMLButtonElement, MouseEvent> & MouseEvent) {
setLoading(true);
try {
onCancel && (await onCancel(e));
} catch (e) {}
setIsOpen(false);
setLoading(false);
}
async function handleConfirm(e: React.MouseEvent<HTMLButtonElement, MouseEvent> & MouseEvent) {
setLoading(true);
try {
onConfirm && (await onConfirm(e));
} catch (e) {}
setIsOpen(false);
setLoading(false);
}
return (
<Overlay usePortal={usePortal} isOpen={isOpen} {...other} onClose={onClose} className={cls}>
<div className={`${prefixCls}-container`}>
<div
className={[
`${prefixCls}-inner`,
title ? `${prefixCls}-shown-title` : null,
icon ? `${prefixCls}-shown-icon` : null,
]
.filter(Boolean)
.join(' ')
.trim()}
style={{ maxWidth, minWidth, width }}
>
{(title || icon) && (
<div className={`${prefixCls}-header`}>
{icon && <Icon type={icon} />}
{title && <h4>{title}</h4>}
{isCloseButtonShown && <Button basic onClick={(e) => handleCancel(e)} icon="close" type="light" />}
const [loading, setLoading] = useState(false);
const cls = [prefixCls, className, type ? `${type}` : null].filter(Boolean).join(' ').trim();
function onClose() {
setIsOpen(false);
}
async function handleCancel(e: React.MouseEvent<HTMLButtonElement, MouseEvent> & MouseEvent) {
setLoading(true);
try {
onCancel && (await onCancel(e));
} catch (e) {}
setIsOpen(false);
setLoading(false);
}
async function handleConfirm(e: React.MouseEvent<HTMLButtonElement, MouseEvent> & MouseEvent) {
setLoading(true);
try {
onConfirm && (await onConfirm(e));
} catch (e) {}
setIsOpen(false);
setLoading(false);
}
return (
<Overlay usePortal={usePortal} isOpen={isOpen} {...other} onClose={onClose} className={cls}>
<div className={`${prefixCls}-container`}>
<div
className={[
`${prefixCls}-inner`,
title ? `${prefixCls}-shown-title` : null,
icon ? `${prefixCls}-shown-icon` : null,
]
.filter(Boolean)
.join(' ')
.trim()}
style={{ maxWidth, minWidth, width }}
>
{(title || icon) && (
<div className={`${prefixCls}-header`}>
{icon && <Icon type={icon} />}
{title && <h4>{title}</h4>}
{isCloseButtonShown && <Button basic onClick={(e) => handleCancel(e)} icon="close" type="light" />}
</div>
)}
<div className={`${prefixCls}-body`} style={bodyStyle}>
{children || content}
</div>
)}
<div className={`${prefixCls}-body`} style={bodyStyle}>
{children || content}
</div>
{useButton && (
<div className={`${prefixCls}-footer`}>
<Button
autoFocus={autoFocus}
type={type}
loading={loading}
disabled={loading}
{...confirmButtonProps}
onClick={(e) => handleConfirm(e)}
>
{confirmText}
</Button>
{cancelText && (
<Button {...cancelButtonProps} onClick={(e) => handleCancel(e)}>
{cancelText}
{useButton && (
<div className={`${prefixCls}-footer`}>
<Button
autoFocus={autoFocus}
type={type}
loading={loading}
disabled={loading}
{...confirmButtonProps}
onClick={(e) => handleConfirm(e)}
>
{confirmText}
</Button>
)}
</div>
)}
{cancelText && (
<Button {...cancelButtonProps} onClick={(e) => handleCancel(e)}>
{cancelText}
</Button>
)}
</div>
)}
</div>
</div>
</div>
</Overlay>
);
});
</Overlay>
);
});

Modal.show = CallShow;
export default Modal;
4 changes: 2 additions & 2 deletions packages/react-overlay/src/index.tsx
Expand Up @@ -61,7 +61,8 @@ export default function Overlay(props: OverlayProps) {
...otherProps
} = props;

const [isOpen, setIsOpen] = useState(props.isOpen || false);
const [isOpen, setIsOpen] = useState<boolean>();
// const [isOpen, setIsOpen] = useState(props.isOpen || false);
const [visible, setVisible] = useState(false);
const container = useRef<HTMLDivElement>(null);
const overlay = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -127,7 +128,6 @@ export default function Overlay(props: OverlayProps) {
// setVisible(false)
// }
}

const TransitionGroupComp = (
<CSSTransition
classNames={transitionName}
Expand Down

0 comments on commit c533549

Please sign in to comment.