109 lines
3.2 KiB
TypeScript
Raw Permalink Normal View History

2024-08-06 14:31:13 +08:00
import React, { useEffect, useRef, useState } from 'react'
import { createPortal } from 'react-dom'
2023-05-15 08:51:32 +08:00
import { useTranslation } from 'react-i18next'
2024-08-06 14:31:13 +08:00
import Button from '../button'
2023-05-15 08:51:32 +08:00
2024-08-06 14:31:13 +08:00
export type IConfirm = {
2023-05-15 08:51:32 +08:00
className?: string
isShow: boolean
type?: 'info' | 'warning'
title: string
2024-08-06 14:31:13 +08:00
content?: React.ReactNode
confirmText?: string | null
2023-05-15 08:51:32 +08:00
onConfirm: () => void
cancelText?: string
onCancel: () => void
2024-08-06 14:31:13 +08:00
isLoading?: boolean
isDisabled?: boolean
showConfirm?: boolean
showCancel?: boolean
maskClosable?: boolean
2023-05-15 08:51:32 +08:00
}
2024-08-06 14:31:13 +08:00
function Confirm({
2023-05-15 08:51:32 +08:00
isShow,
type = 'warning',
title,
content,
confirmText,
cancelText,
onConfirm,
onCancel,
2024-08-06 14:31:13 +08:00
showConfirm = true,
showCancel = true,
isLoading = false,
isDisabled = false,
maskClosable = true,
2023-05-15 08:51:32 +08:00
}: IConfirm) {
const { t } = useTranslation()
2024-08-06 14:31:13 +08:00
const dialogRef = useRef<HTMLDivElement>(null)
const [isVisible, setIsVisible] = useState(isShow)
2023-05-15 08:51:32 +08:00
const confirmTxt = confirmText || `${t('common.operation.confirm')}`
const cancelTxt = cancelText || `${t('common.operation.cancel')}`
2024-08-06 14:31:13 +08:00
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Escape')
onCancel()
if (event.key === 'Enter' && isShow) {
event.preventDefault()
onConfirm()
}
2024-08-06 14:31:13 +08:00
}
document.addEventListener('keydown', handleKeyDown)
return () => {
document.removeEventListener('keydown', handleKeyDown)
}
}, [onCancel, onConfirm, isShow])
2024-08-06 14:31:13 +08:00
const handleClickOutside = (event: MouseEvent) => {
if (maskClosable && dialogRef.current && !dialogRef.current.contains(event.target as Node))
onCancel()
}
useEffect(() => {
document.addEventListener('mousedown', handleClickOutside)
return () => {
document.removeEventListener('mousedown', handleClickOutside)
}
}, [maskClosable])
2023-05-15 08:51:32 +08:00
2024-08-06 14:31:13 +08:00
useEffect(() => {
if (isShow) {
setIsVisible(true)
}
else {
const timer = setTimeout(() => setIsVisible(false), 200)
return () => clearTimeout(timer)
}
}, [isShow])
if (!isVisible)
return null
return createPortal(
<div className={'fixed inset-0 z-[10000000] flex items-center justify-center bg-background-overlay'}
2024-08-06 14:31:13 +08:00
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
}}>
<div ref={dialogRef} className={'relative w-full max-w-[480px] overflow-hidden'}>
<div className='shadows-shadow-lg flex max-w-full flex-col items-start rounded-2xl border-[0.5px] border-solid border-components-panel-border bg-components-panel-bg'>
<div className='flex flex-col items-start gap-2 self-stretch pb-4 pl-6 pr-6 pt-6'>
2024-08-06 14:31:13 +08:00
<div className='title-2xl-semi-bold text-text-primary'>{title}</div>
<div className='system-md-regular w-full text-text-tertiary'>{content}</div>
2024-08-06 14:31:13 +08:00
</div>
<div className='flex items-start justify-end gap-2 self-stretch p-6'>
2024-08-06 14:31:13 +08:00
{showCancel && <Button onClick={onCancel}>{cancelTxt}</Button>}
{showConfirm && <Button variant={'primary'} destructive={type !== 'info'} loading={isLoading} disabled={isDisabled} onClick={onConfirm}>{confirmTxt}</Button>}
2023-05-15 08:51:32 +08:00
</div>
</div>
2024-08-06 14:31:13 +08:00
</div>
</div>, document.body,
2023-05-15 08:51:32 +08:00
)
}
2024-08-06 14:31:13 +08:00
export default React.memo(Confirm)