import { forwardRef, ReactNode, ForwardRefExoticComponent, useImperativeHandle, CSSProperties, } from 'react' import classNames from 'classnames' import { Popup, PopupProps } from '../popup/Popup' import { Button, ButtonProps } from '../button/Button' import { Icon } from '../icon/Icon' import { show, alert, confirm } from './DialogImperative' import { CommonComponentProps } from '../../utils/types' import './Dialog.scss' import { useEvent } from '../../use' const CANCEL = 'cancel' const CONFIRM = 'confirm' type CloseType = 'cancel' | 'confirm' export interface DialogRef { clear: () => void reset: () => void } type DialogButtonType = 'rounded' | 'text' export interface DialogProps extends CommonComponentProps { className?: string style?: CSSProperties children?: ReactNode maskClosable?: boolean title?: ReactNode message?: ReactNode header?: ReactNode headed?: boolean footer?: ReactNode buttonType?: DialogButtonType showCancel?: boolean cancelText?: ReactNode cancelProps?: ButtonProps showConfirm?: boolean confirmText?: ReactNode confirmProps?: ButtonProps onCancel?: () => void onConfirm?: () => void beforeClose?: (done: () => void, type: CloseType) => void onDone?: () => void visible?: boolean popupProps?: PopupProps } export interface Dialog extends ForwardRefExoticComponent { show: (props: DialogProps) => any alert: (props: DialogProps) => any confirm: (props: DialogProps) => any } export interface DialogImperative {} const buttonProps: { [p in DialogButtonType]: { [p in 'cancel' | 'confirm']: ButtonProps } } = { text: { cancel: { type: 'text', theme: 'secondary', size: 'large', }, confirm: { type: 'text', theme: 'primary', size: 'large', }, }, rounded: { cancel: { type: 'secondary', theme: 'primary', rounded: true, }, confirm: { type: 'primary', theme: 'primary', rounded: true, }, }, } export const Dialog = forwardRef( (props, ref) => { const { className, children, maskClosable = false, title, message, header, footer, buttonType = 'text', headed, showCancel = false, cancelText = '取消', cancelProps, showConfirm = true, confirmText = '确定', confirmProps, onCancel, onConfirm, beforeClose, onDone, visible = false, popupProps = {}, ...restProps } = props const { mask = true, placement = 'center', onMaskClick, ...restPopupProps } = popupProps const handleMaskClick = useEvent(() => { if (maskClosable) { onCancel?.() } onMaskClick?.() }) const handleClose = () => { perhapsClose(CANCEL, onCancel) } const handleCancel = () => { perhapsClose(CANCEL, onCancel) } const handleConfirm = () => { perhapsClose(CONFIRM, onConfirm) } const perhapsClose = ( type: CloseType, callback: (() => void) | undefined ) => { if (beforeClose) { beforeClose(() => { onDone?.() callback?.() }, type) } else { callback?.() } } useImperativeHandle(ref, () => ({})) const dialogClass = classNames( 's-dialog', { 's-dialog-headed': headed, 's-dialog-untitled': !title, 's-dialog-rounded-button': buttonType === 'rounded', }, className ) const renderTitle = () => { return
{title}
} return (
{headed && (
{header || renderTitle()}
)}
{children || ( <> {!headed && title && renderTitle()} {message &&
{message}
} )}
{footer || ( <> {showCancel && ( )} {showConfirm && ( )} )}
) } ) as Dialog Dialog.show = show Dialog.alert = alert Dialog.confirm = confirm export default Dialog