/
kaws
/
ui-kit-ce
Обзор
Документация
Войти
/
kaws
/
ui-kit-ce
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
packages/notification/src/hooks/useNotificationContainer.ts
225 строк
6 KB
Урядышев Павел Александрович
chore: устранены предупреждения eslint
25 июл 2025, 14:03
25 июл 2025, 14:03
1bad2f7
Код
Авторство
О чём код?
import * as React from 'react' import { eventManager } from '../core/notification' import { NotificationContainerProps, TNotificationPosition, NotificationProps, NotificationObject, } from '../types' import { mergeClasses } from '@v-uik/utils' import { clsx } from '@v-uik/theme' type NotificationByIdMap = Record<string, NotificationObject> export type NotificationsToRender = Partial< Record<TNotificationPosition, NotificationObject[]> > export interface UseNotificationContainerValue { /** * * @inner */ notificationsToRender: NotificationsToRender /** * * @returns */ isNotificationActive: (id: string) => boolean } export const useNotificationContainer = ( props: NotificationContainerProps ): UseNotificationContainerValue => { const [, forceUpdate] = React.useReducer((x: number) => x + 1, 0) const [showingNotificationIds, setShowingNotificationIds] = React.useState< string[] >([]) const notificationsCount = React.useRef(0) const notificationsQueue = React.useRef<NotificationObject[]>([]) const notificationByIdMap = React.useRef<NotificationByIdMap>({}) const propsRef = React.useRef(props) React.useEffect(() => { propsRef.current = props }) const isNotificationActive = (id: string) => { return showingNotificationIds.includes(id) } React.useEffect(() => { const clearWaitingQueue = () => { if (propsRef.current.limit) { notificationsCount.current -= notificationsQueue.current.length notificationsQueue.current = [] } } const appendNotification = ( content: React.ReactNode, props: NotificationProps ) => { if (props.id) { notificationByIdMap.current[props.id] = { content, props, } setShowingNotificationIds((prevState) => [ ...prevState, props.id as string, ]) } } const removeNotification = (notificationId: string) => { setShowingNotificationIds((prevState) => prevState.filter((id) => id !== notificationId) ) } const removeAllNotifications = () => { setShowingNotificationIds([]) } const removeCompletelyFromStore = (notificationId: string) => { delete notificationByIdMap.current[notificationId] notificationsCount.current = (notificationsCount.current || 1) - 1 if (notificationsQueue.current.length) { dequeueNotification() } else { forceUpdate() } } const dequeueNotification = () => { const notification = notificationsQueue.current.shift() if (notification) { appendNotification(notification.content, notification.props) } } const createNotification = ( options: NotificationProps & { /** * */ content: React.ReactNode } ) => { const { id, content } = options if (id && notificationByIdMap.current[id]) { return } notificationsCount.current++ const closeNotification = () => removeNotification(id as string) const notificationProps: NotificationProps = { ...options, closeNotification, position: options.position || propsRef.current.position, classes: mergeClasses({ classes1: propsRef.current.notificationClasses || {}, classes2: options.classes || {}, mergeCallback: clsx, }), closeButtonProps: options.closeButtonProps || propsRef.current.closeButtonProps, nextNotification: options.nextNotification || propsRef.current.nextNotification, closeButtonAriaLabel: options.closeButtonAriaLabel || propsRef.current.closeButtonAriaLabel, closeOnEscapeKeyDown: typeof options.closeOnEscapeKeyDown === 'boolean' ? options.closeOnEscapeKeyDown : propsRef.current.closeOnEscapeKeyDown, pauseOnHover: typeof options.pauseOnHover === 'boolean' ? options.pauseOnHover : propsRef.current.pauseOnHover, pauseOnWindowBlur: typeof options.pauseOnWindowBlur === 'boolean' ? options.pauseOnWindowBlur : propsRef.current.pauseOnWindowBlur, closeOnClick: typeof options.closeOnClick === 'boolean' ? options.closeOnClick : propsRef.current.closeOnClick, autoClose: options.autoClose !== undefined ? options.autoClose : propsRef.current.autoClose, showCloseButton: typeof options.showCloseButton === 'boolean' ? options.showCloseButton : propsRef.current.showCloseButton, showIndicator: typeof options.showIndicator === 'boolean' ? options.showIndicator : propsRef.current.showIndicator, removeNotification: () => removeCompletelyFromStore(options.id as string), } let notificationContent = content if (React.isValidElement(content) && typeof content.type !== 'string') { notificationContent = React.cloneElement(content, { closeNotification, notificationProps, }) } const limit = propsRef.current.limit if (limit && limit > 0 && notificationsCount.current > limit) { notificationsQueue.current.push({ content: notificationContent, props: notificationProps, }) } else { appendNotification(notificationContent, notificationProps) } } eventManager .on('Show', createNotification) .on('Remove', removeNotification) .on('ClearAll', removeAllNotifications) .on('ClearWaitingQueue', clearWaitingQueue) return () => { eventManager .off('Show', createNotification) .off('Remove', removeNotification) .off('ClearAll', removeAllNotifications) .off('ClearWaitingQueue', clearWaitingQueue) } }, []) // eslint-disable-line react-hooks/exhaustive-deps const notificationsToRender: NotificationsToRender = {} const notificationsIds = Object.keys(notificationByIdMap.current) notificationsIds.forEach((id) => { const notification = notificationByIdMap.current[id] const { position } = notification.props if (position) { if (!notificationsToRender[position]) { notificationsToRender[position] = [] } notificationsToRender[position]?.push(notification) } }) return { notificationsToRender, isNotificationActive, } }