@mui/x-charts
Version:
The community edition of MUI X Charts components.
100 lines (94 loc) • 3.89 kB
JavaScript
;
'use client';
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ChartsAccessibilityProxy = ChartsAccessibilityProxy;
var React = _interopRequireWildcard(require("react"));
var _useChartId = require("../../../hooks/useChartId");
var _useDescription = require("./useDescription");
var _jsxRuntime = require("react/jsx-runtime");
/**
* Make the proxy looks like a layer.
* Having a non-zero size is important for some screen readers to announce the content.
*/const fullSizeLayerStyle = {
borderWidth: 0,
width: '100%',
height: '100%',
overflow: 'hidden',
position: 'absolute',
inset: 0,
padding: 0,
outline: 'none',
pointerEvents: 'none'
};
// The proxy is implemented by having two divs with the same content, and toggling the visibility of each one when the content changes.
// The idea is to imitate the behavior of the focus moving from a list element to another, but with the minimal number of DOM elements.
/**
* This component provides an accessibility proxy for charts.
* It uses two divs to let screen readers announce the focused content when it changes.
*/
function ChartsAccessibilityProxy() {
const message = (0, _useDescription.useDescription)();
const chartId = (0, _useChartId.useChartId)();
const currentFormatRef = React.useRef(null);
const currentIndexRef = React.useRef(0);
const containerRef = React.useRef(null);
React.useEffect(() => {
const container = containerRef.current;
if (!container) {
return;
}
// Initialize children if not present
if (container.children.length === 0) {
for (let i = 0; i < 2; i += 1) {
const div = document.createElement('div');
div.setAttribute('id', i === 0 ? `voiceover-${chartId}-1` : `voiceover-${chartId}-2`);
div.style.display = 'none';
container.appendChild(div);
}
// The divs with the message content
for (let i = 0; i < 2; i += 1) {
const div = document.createElement('div');
if (i === (currentIndexRef.current + 1) % 2 && message) {
div.setAttribute('tabindex', '0');
}
div.setAttribute('role', 'img');
div.setAttribute('aria-labelledby', i === 0 ? `voiceover-${chartId}-1` : `voiceover-${chartId}-2`);
div.style.width = '100%';
div.style.height = '100%';
div.style.outline = 'none';
container.appendChild(div);
}
}
if (message && message !== currentFormatRef.current) {
currentFormatRef.current = message;
const inactiveIndex = currentIndexRef.current;
currentIndexRef.current = (currentIndexRef.current + 1) % 2;
const activeIndex = currentIndexRef.current;
const activeDiv = container.children[2 + activeIndex];
const inactiveDiv = container.children[2 + inactiveIndex];
const activeTextDiv = container.children[activeIndex];
const inactiveTextDiv = container.children[inactiveIndex];
// Both get text update
activeTextDiv.textContent = message ?? '';
inactiveTextDiv.textContent = message ?? '';
activeDiv.setAttribute('aria-hidden', 'false');
activeDiv.setAttribute('aria-labelledby', activeIndex === 0 ? `voiceover-${chartId}-1` : `voiceover-${chartId}-2`);
if (message) {
activeDiv.setAttribute('tabindex', '0');
}
inactiveDiv.setAttribute('aria-hidden', 'true');
inactiveDiv.setAttribute('aria-labelledby', activeIndex === 0 ? `voiceover-${chartId}-1` : `voiceover-${chartId}-2`);
inactiveDiv.removeAttribute('tabindex');
activeDiv.focus();
}
}, [message, chartId]);
return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
role: "presentation",
tabIndex: message ? undefined : 0,
ref: containerRef,
style: fullSizeLayerStyle
});
}