import { CloseOutlined } from "@ant-design/icons"; import classNames from "classnames"; import type { CSSMotionProps } from "rc-motion"; import { useNotification as useRcNotification } from 'rc-notification'; import type { NotificationAPI, NotificationConfig as RcNotificationConfig } from 'rc-notification'; import type { ReactNode} from "react"; import { useImperativeHandle} from "react"; import { forwardRef} from "react"; import { useMemo, useRef } from "react"; import type { NotificationArgsProps, NotificationConfig, NotificationInstance, NotificationPlacement} from "./protocol"; import { DEFAULT_DURATION} from "./protocol"; import { getPlacementStyle} from "./protocol"; import { DEFAULT_OFFSET} from "./protocol"; import { NOTIFICATION_PREFIX_CLS } from "./protocol"; import { DEFAULT_PLACEMENT } from "./protocol"; import { PureContent } from "./pure-panel"; export function getCloseIcon(prefixCls: string, closeIcon?: ReactNode): ReactNode { if (closeIcon === null || closeIcon === false) { return null; } return closeIcon || ; } type HolderProps = NotificationConfig & { onAllRemoved?: VoidFunction; }; interface HolderRef extends NotificationAPI { prefixCls: string; notification?: RcNotificationConfig; } const Holder = forwardRef(function Holder(props, ref) { const { top, bottom, getContainer: staticGetContainer, maxCount, onAllRemoved, stack, duration, pauseOnHover = true, showProgress, } = props; const prefixCls = NOTIFICATION_PREFIX_CLS // =============================== Style =============================== const getStyle = (placement: NotificationPlacement): React.CSSProperties => getPlacementStyle(placement, top ?? DEFAULT_OFFSET, bottom ?? DEFAULT_OFFSET); function getMotion(prefixCls: string): CSSMotionProps { return { motionName: `${prefixCls}-fade`, }; } // ============================== Motion =============================== const getNotificationMotion = () => getMotion(prefixCls); // ============================== Origin =============================== const [api, holder] = useRcNotification({ prefixCls, style: getStyle, motion: getNotificationMotion, closable: true, closeIcon: getCloseIcon(prefixCls), duration: duration ?? DEFAULT_DURATION, getContainer: () => staticGetContainer?.() || document.body, maxCount, pauseOnHover, showProgress, onAllRemoved, }); // ================================ Ref ================================ useImperativeHandle(ref, () => ({ ...api, prefixCls })); return holder; }); export function useInternalNotification( notificationConfig?: HolderProps, ): readonly [NotificationInstance, React.ReactElement] { const holderRef = useRef(null); // ================================ API ================================ const wrapAPI = useMemo(() => { // Wrap with notification content // >>> Open const open = (config: NotificationArgsProps) => { if (!holderRef.current) { return; } const { open: originOpen, prefixCls, notification } = holderRef.current; const noticePrefixCls = `${prefixCls}-notice`; const { message, description, icon, type, btn, className, style, role = 'alert', closeIcon, closable, ...restConfig } = config; const realCloseIcon = getCloseIcon( noticePrefixCls, typeof closeIcon !== 'undefined' ? closeIcon : notification?.closeIcon, ); return originOpen({ // use placement from props instead of hard-coding "topRight" placement: notificationConfig?.placement ?? DEFAULT_PLACEMENT, ...restConfig, content: ( ), className: classNames( type && `${noticePrefixCls}-${type}`, className, notification?.className, ), style: { ...notification?.style, ...style }, closeIcon: realCloseIcon, closable: closable ?? !!realCloseIcon, }); }; // >>> destroy const destroy = (key?: React.Key) => { if (key !== undefined) { holderRef.current?.close(key); } else { holderRef.current?.destroy(); } }; const clone = { open, destroy, } as NotificationInstance; const keys = ['success', 'info', 'warning', 'error'] as const; keys.forEach((type) => { clone[type] = (config) => open({ ...config, type, }); }); return clone; }, [notificationConfig?.placement]); // ============================== Return =============================== return [ wrapAPI, , ] as const; }