import useState from 'rc-util/lib/hooks/useState'; import * as React from 'react'; import Button from '../button'; import type { ButtonProps, LegacyButtonType } from '../button/button'; import { convertLegacyProps } from '../button/buttonHelpers'; export interface ActionButtonProps { type?: LegacyButtonType; actionFn?: (...args: any[]) => any | PromiseLike; close?: Function; autoFocus?: boolean; prefixCls: string; buttonProps?: ButtonProps; emitEvent?: boolean; quitOnNullishReturnValue?: boolean; children?: React.ReactNode; /** * Do not throw if is await mode */ isSilent?: () => boolean; } function isThenable(thing?: PromiseLike): boolean { return !!(thing && thing.then); } const ActionButton: React.FC = (props) => { const { type, children, prefixCls, buttonProps, close, autoFocus, emitEvent, isSilent, quitOnNullishReturnValue, actionFn, } = props; const clickedRef = React.useRef(false); const buttonRef = React.useRef(null); const [loading, setLoading] = useState(false); const onInternalClose = (...args: any[]) => { close?.(...args); }; React.useEffect(() => { let timeoutId: ReturnType | null = null; if (autoFocus) { timeoutId = setTimeout(() => { buttonRef.current?.focus(); }); } return () => { if (timeoutId) { clearTimeout(timeoutId); } }; }, []); const handlePromiseOnOk = (returnValueOfOnOk?: PromiseLike) => { if (!isThenable(returnValueOfOnOk)) { return; } setLoading(true); returnValueOfOnOk!.then( (...args: any[]) => { setLoading(false, true); onInternalClose(...args); clickedRef.current = false; }, (e: Error) => { // See: https://github.com/ant-design/ant-design/issues/6183 setLoading(false, true); clickedRef.current = false; // Do not throw if is `await` mode if (isSilent?.()) { return; } return Promise.reject(e); }, ); }; const onClick = (e: React.MouseEvent) => { if (clickedRef.current) { return; } clickedRef.current = true; if (!actionFn) { onInternalClose(); return; } let returnValueOfOnOk: PromiseLike; if (emitEvent) { returnValueOfOnOk = actionFn(e); if (quitOnNullishReturnValue && !isThenable(returnValueOfOnOk)) { clickedRef.current = false; onInternalClose(e); return; } } else if (actionFn.length) { returnValueOfOnOk = actionFn(close); // https://github.com/ant-design/ant-design/issues/23358 clickedRef.current = false; } else { returnValueOfOnOk = actionFn(); if (!returnValueOfOnOk) { onInternalClose(); return; } } handlePromiseOnOk(returnValueOfOnOk); }; return ( ); }; export default ActionButton;