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
JavaScript
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