mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 22:04:56 +00:00
103 lines
2.6 KiB
TypeScript
103 lines
2.6 KiB
TypeScript
'use client'
|
||
|
||
import React, { useEffect, useCallback } from 'react'
|
||
import { classNames } from '../utils/classNames'
|
||
|
||
export type NotificationType = 'success' | 'error' | 'warning' | 'info'
|
||
export type NotificationPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center'
|
||
|
||
export interface NotificationData {
|
||
id: string
|
||
type: NotificationType
|
||
message: string
|
||
duration?: number
|
||
}
|
||
|
||
export interface NotificationContainerProps {
|
||
notifications: NotificationData[]
|
||
onClose: (id: string) => void
|
||
position?: NotificationPosition
|
||
maxVisible?: number
|
||
className?: string
|
||
testId?: string
|
||
}
|
||
|
||
const ICONS: Record<NotificationType, string> = {
|
||
success: '✓',
|
||
error: '✕',
|
||
warning: '⚠',
|
||
info: 'ℹ',
|
||
}
|
||
|
||
interface NotificationItemProps {
|
||
notification: NotificationData
|
||
onClose: (id: string) => void
|
||
}
|
||
|
||
const NotificationItem: React.FC<NotificationItemProps> = ({ notification, onClose }) => {
|
||
const { id, type, message, duration = 5000 } = notification
|
||
|
||
useEffect(() => {
|
||
if (duration > 0) {
|
||
const timer = setTimeout(() => onClose(id), duration)
|
||
return () => clearTimeout(timer)
|
||
}
|
||
}, [id, duration, onClose])
|
||
|
||
const rootClass = classNames(
|
||
'fakemui-notification',
|
||
`fakemui-notification--${type}`
|
||
)
|
||
|
||
return (
|
||
<div className={rootClass} role="alert" aria-live="polite">
|
||
<span className="fakemui-notification__icon">{ICONS[type]}</span>
|
||
<span className="fakemui-notification__message">{message}</span>
|
||
<button
|
||
className="fakemui-notification__close"
|
||
onClick={() => onClose(id)}
|
||
aria-label="Close notification"
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export const NotificationContainer: React.FC<NotificationContainerProps> = ({
|
||
notifications,
|
||
onClose,
|
||
position = 'top-right',
|
||
maxVisible = 5,
|
||
className = '',
|
||
testId,
|
||
}) => {
|
||
const handleClose = useCallback((id: string) => {
|
||
onClose(id)
|
||
}, [onClose])
|
||
|
||
const visibleNotifications = notifications.slice(0, maxVisible)
|
||
|
||
if (visibleNotifications.length === 0) return null
|
||
|
||
const rootClass = classNames(
|
||
'fakemui-notification-container',
|
||
`fakemui-notification-container--${position}`,
|
||
className
|
||
)
|
||
|
||
return (
|
||
<div className={rootClass} data-testid={testId} role="region" aria-label="Notifications" aria-live="polite">
|
||
{visibleNotifications.map((notification) => (
|
||
<NotificationItem
|
||
key={notification.id}
|
||
notification={notification}
|
||
onClose={handleClose}
|
||
/>
|
||
))}
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default NotificationContainer
|