/**
* @file modal 的内部逻辑处理,抽出来可以分别提供给 Modal 和 Dialog
*/
import React, { useCallback, useMemo, useRef } from 'react'
import { DialogProps } from 'rc-dialog'
import cn from 'classnames'
import { useMask } from '../ConfigProvider'
import { MaskProps } from '../internal/Mask'
import { useLayer } from '../internal/Mask/layer'
import { concat } from '../utils'
import { useValue } from '../utils/hooks'
import { CloseIcon } from '../icons'
import { PopupContainerProvider } from '../PopupContainerProvider'
import Footer, { footerCtx } from './Footer'
import { InternalModalProps as ModalProps } from './Modal'
export type UseModalPropsReturn = {
handleOk: () => void
handleCancel: () => void
maskProps: MaskProps
rcDialogProps: DialogProps
}
export function useModalProps(props: ModalProps, prefix: string): UseModalPropsReturn {
const {
footer = , onOk, onCancel, width, title,
visible: visibleFromProps, style, rootHtmlProps,
maskHtmlProps, autoDestroy = false, maskClickable: maskClickableFromProps,
children, className, keyboard = true, renderModal, centered = false
} = props
const maskConfig = useMask().modal
const { value: visible, setValue: setVisible } = useValue(
{ valueFromProps: visibleFromProps, defaultValue: true }
)
const maskClickable = maskClickableFromProps ?? maskConfig.clickable
const { zIndex } = useLayer(visible, 'Modal')
const titlePopupContainerRef = useRef(null)
const bodyPopupContainerRef = useRef(null)
const footerPopupContainerRef = useRef(null)
const handleOk = useCallback(async () => {
await onOk?.()
setVisible(false)
}, [onOk, setVisible])
const handleCancel = useCallback(() => {
onCancel?.()
setVisible(false)
}, [onCancel, setVisible])
const handleMaskClick = useCallback((e: React.MouseEvent) => {
maskHtmlProps?.onClick?.(e)
if (e.defaultPrevented) return
if (!maskClickable) return
handleCancel()
}, [maskHtmlProps, maskClickable, handleCancel])
const footerCtxValue = useMemo(() => ({
onOk: handleOk,
onCancel: handleCancel
}), [handleOk, handleCancel])
const titleView = title && (
<>
{title}
>
)
const footerView = footer && (
{footer}
)
const realChildren = (
<>
{children}
>
)
return {
handleOk,
handleCancel,
maskProps: {
...maskHtmlProps,
visible,
onClick: handleMaskClick,
autoDestroy,
keyboard,
onKeyboard: handleCancel
},
rcDialogProps: {
prefixCls: prefix,
wrapProps: rootHtmlProps,
visible,
mask: false,
// mask 设置为 false 后还需要设置这个才能允许点击到 Mask 不关闭
maskClosable: maskClickable,
footer: footerView,
closeIcon: ,
width,
style,
onClose: handleCancel,
children: realChildren,
title: titleView,
className,
keyboard: false,
modalRender: renderModal,
classNames: {
wrapper: cn(centered && concat(prefix, 'wrap', 'centered'))
},
styles: {
wrapper: {
zIndex: zIndex + 1
}
}
}
}
}