UNPKG

zentrixui

Version:

ZentrixUI - A modern, highly customizable and accessible React file upload component library with multiple variants, JSON-based configuration, and excellent developer experience.

94 lines (93 loc) 3.29 kB
import { jsxs, Fragment, jsx } from "react/jsx-runtime"; import React__default, { useState, useRef, useEffect, useCallback } from "react"; import { shouldAnnounceError, createErrorAnnouncement } from "../../utils/error-handling.js"; const AccessibilityAnnouncer = ({ errors = [], announceErrors = true, announceProgress = true, announceFileSelection = true, politeAnnouncements = false, className = "" }) => { const [announcements, setAnnouncements] = useState([]); const [currentAnnouncement, setCurrentAnnouncement] = useState(""); const announcementTimeoutRef = useRef(); const processedErrorsRef = useRef(/* @__PURE__ */ new Set()); useEffect(() => { if (!announceErrors || errors.length === 0) return; const newErrors = errors.filter( (error) => !processedErrorsRef.current.has(error.id) && shouldAnnounceError(error) ); if (newErrors.length === 0) return; const newAnnouncements = newErrors.map((error) => ({ id: `error-${error.id}`, message: createErrorAnnouncement(error), priority: error.severity === "critical" || error.severity === "high" ? "assertive" : "polite", timestamp: /* @__PURE__ */ new Date() })); newErrors.forEach((error) => { processedErrorsRef.current.add(error.id); }); setAnnouncements((prev) => [...prev, ...newAnnouncements]); }, [errors, announceErrors]); useEffect(() => { if (announcements.length === 0) return; const processNextAnnouncement = () => { const nextAnnouncement = announcements[0]; if (!nextAnnouncement) return; setCurrentAnnouncement(nextAnnouncement.message); setAnnouncements((prev) => prev.slice(1)); announcementTimeoutRef.current = setTimeout(() => { setCurrentAnnouncement(""); }, 1e3); }; if (!currentAnnouncement) { processNextAnnouncement(); } else { const timeout = setTimeout(processNextAnnouncement, 1500); return () => clearTimeout(timeout); } }, [announcements, currentAnnouncement]); useEffect(() => { return () => { if (announcementTimeoutRef.current) { clearTimeout(announcementTimeoutRef.current); } }; }, []); const announce = useCallback((message, priority = "polite") => { const announcement = { id: `custom-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`, message, priority, timestamp: /* @__PURE__ */ new Date() }; setAnnouncements((prev) => [...prev, announcement]); }, []); React__default.useImperativeHandle(React__default.forwardRef(() => null), () => ({ announce })); const liveRegionProps = { "aria-live": politeAnnouncements ? "polite" : "assertive", "aria-atomic": true, role: "status", className: `sr-only ${className}`.trim() }; return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx("div", { ...liveRegionProps, children: currentAnnouncement }), /* @__PURE__ */ jsx( "div", { "aria-live": "polite", "aria-atomic": "true", role: "status", className: "sr-only" } ) ] }); }; AccessibilityAnnouncer.displayName = "AccessibilityAnnouncer"; export { AccessibilityAnnouncer }; //# sourceMappingURL=accessibility-announcer.js.map