import { createContext, CSSProperties, ForwardRefExoticComponent, ReactNode, useEffect, useRef, useState, } from 'react' import classNames from 'classnames' import { CommonComponentProps } from '../../utils/types' import { Popup, PopupProps } from '../popup/Popup' import { Button, ButtonProps } from '../button/Button' import { Icon } from '../icon/Icon' import { useEvent } from '../../use' import './Popout.scss' import PopoutBridge from './PopoutBridge' import PopoutTarget from './PopoutTarget' import PopoutOutlet from './PopoutOutlet' import PopoutClear from './PopoutClear' import PopoutSelect from './PopoutSelect' export * from './PopoutBridge' export * from './PopoutTarget' export * from './PopoutOutlet' export interface PopoutProps extends CommonComponentProps { className?: string style?: CSSProperties title?: ReactNode children?: ReactNode visible?: boolean defaultVisible?: boolean onVisible?: (visible: boolean) => void showCancel?: boolean cancelText?: ReactNode cancelProps?: ButtonProps showConfirm?: boolean confirmText?: ReactNode confirmProps?: ButtonProps type?: 'compact' | 'loose' onClose?: (visible: false) => void onCancel?: (visible: false) => void onConfirm?: (visible: false) => void popupProps?: PopupProps } export interface Popout extends ForwardRefExoticComponent { Bridge: PopoutBridge } export interface PopoutContext { setTarget: (target?: ReactNode) => void setVisible: (visible: boolean) => void setChangeArgs: (...args: any[]) => void setConfirmDisabled: (disabled: boolean) => void setEnter: (callback: Function) => void setTmpChangeArgs: (...args: any[]) => void clear: () => void } export const PopoutContext = createContext({} as PopoutContext) export type PopoutChangeArgsContext = any[] export const PopoutChangeArgsContext = createContext( [] ) export function Popout(props: PopoutProps) { const { className, title, children, visible, defaultVisible, onVisible, showCancel = false, cancelText = '取消', cancelProps, showConfirm = true, confirmText = '确定', confirmProps, type = 'loose', onClose, onCancel, onConfirm, popupProps = {}, ...restProps } = props const { placement = 'bottom', onMaskClick, onEnter, ...restPopupProps } = popupProps const [innerVisible, setInnerVisible] = useState( visible ?? defaultVisible ?? false ) const setVisible = (show: boolean) => { // 非受控 if (visible == null) { setInnerVisible(show) } onVisible?.(show) } // 受控 useEffect(() => { if (visible != null) { setInnerVisible(visible) } }, [visible]) const handleMaskClick = useEvent(() => { setVisible(false) onClose?.(false) onMaskClick?.() }) const handleCancel = useEvent(() => { setVisible(false) onCancel?.(false) onClose?.(false) }) const handleConfirm = useEvent(() => { setChangeArgs(tmpChangeArgs.current.slice()) setVisible(false) onConfirm?.(false) onClose?.(false) }) const [target, setTarget] = useState(null) const enter = useRef() const handleEnter = useEvent(() => { enter.current?.() onEnter?.() }) const [changeArgs, setChangeArgs] = useState([]) const tmpChangeArgs = useRef([]) const [confirmDisabled, setConfirmDisabled] = useState(false) const clear = useEvent(() => { if (changeArgs.length !== 0) { setChangeArgs([]) } }) const popoutContext = useRef({ setTarget, setVisible, setChangeArgs, setConfirmDisabled, setEnter: (callback) => { enter.current = callback }, setTmpChangeArgs: (changeArgs) => { tmpChangeArgs.current = changeArgs }, clear, }) const popoutClass = classNames('s-popout', 's-popout-' + type, className) return ( <> {target}
{type === 'compact' && ( )} {title &&
{title}
} {type === 'compact' && ( )} {type === 'loose' && ( )}
{children}
{type === 'loose' && (
{showCancel && ( )} {showConfirm && ( )}
)}
) } Popout.Bridge = PopoutBridge Popout.Target = PopoutTarget Popout.Outlet = PopoutOutlet Popout.Clear = PopoutClear Popout.Select = PopoutSelect export default Popout