packages/bui-core/src/Dialog/FunctionalDialog.tsx (133 lines of code) (raw):

import React, { LegacyRef, useCallback, useEffect, useState } from 'react'; import { getRootElement, render, unmount } from '@bifrostui/utils'; import Popup from './Dialog'; import { DialogPromise, DialogInstance, PromptOptions, ConfirmOptions, DialogOptions, Dispatch, DialogFunction, DialogRef, } from './Dialog.types'; const { isValidElement, Component } = React; /** * 参数格式化,支持直接传文案 */ const formatProps = (props) => { if (typeof props === 'string' || isValidElement(props)) { return { message: props }; } return props; }; const DialogGenerator = (options: DialogOptions) => { const rootWrapper = document.createElement('div'); const rootElement = getRootElement(); rootElement.appendChild(rootWrapper); const DialogComponent = () => { const { onConfirm, onCancel, ref, ...others } = options; const [visible, setVisible] = useState(false); const close = useCallback(() => { setVisible(false); setTimeout(() => { const unmountRes = unmount(rootWrapper); if (unmountRes && rootWrapper.parentNode) { rootWrapper.parentNode.removeChild(rootWrapper); } }, 150); }, [rootWrapper]); useEffect(() => { setVisible(true); }, []); const dispatch: Dispatch = async (action, val) => { if (action === true) { try { await onConfirm?.(val); } catch (error) { /* empty */ } } else if (action === false) { try { await onCancel?.(); } catch (error) { /* empty */ } } close(); }; return ( <Popup ref={ref as LegacyRef<DialogRef>} {...others} open={visible} onOk={(val) => dispatch(true, val)} onClose={() => dispatch(false)} /> ); }; return render(<DialogComponent />, rootWrapper); }; const Dialog: DialogInstance = ( props: DialogOptions | string, ): DialogPromise => { const options = formatProps(props); const { onConfirm, onCancel, ...rest } = options; return new Promise((resolve) => { DialogGenerator({ ...rest, onConfirm: async (val) => { await onConfirm?.(val); if (rest.type === 'prompt') resolve(val); else resolve(true); }, onCancel: async () => { await onCancel?.(); resolve(false); }, }); }); }; Dialog.prototype = Component.prototype; const confirm = (options: ConfirmOptions) => { return Dialog({ type: 'confirm', ...formatProps(options), }); }; const prompt = (options: PromptOptions) => { return Dialog({ type: 'prompt', ...formatProps(options), }); }; const useDialog = () => { const holderRef = React.useRef(null); const wrapAPI: DialogFunction = ( props: DialogOptions | string, ): DialogPromise => { const options = { theme: holderRef.current?.theme, ...formatProps(props) }; const { onConfirm, onCancel, ...rest } = options; return new Promise((resolve) => { DialogGenerator({ ...rest, onConfirm: async (val) => { await onConfirm?.(val); if (rest.type === 'prompt') resolve(val); else resolve(true); }, onCancel: async () => { await onCancel?.(); resolve(false); }, }); }); }; wrapAPI.confirm = (options: ConfirmOptions) => Dialog({ type: 'confirm', ...formatProps(options), theme: holderRef.current?.theme, }); wrapAPI.prompt = (options: PromptOptions) => Dialog({ type: 'prompt', ...formatProps(options), theme: holderRef.current?.theme, }); return [wrapAPI, <Popup key="dialog-holder" ref={holderRef} />] as [ DialogFunction, React.JSX.Element, ]; }; Dialog.confirm = confirm; Dialog.prompt = prompt; Dialog.useDialog = useDialog; export default Dialog;