File size: 2,887 Bytes
bc20498 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
import { isBrowser, isHTMLElement, styleToString } from '../index.js';
/**
* Creates or gets an announcer element which is used to announce messages to screen readers.
* Within the date components, we use this to announce when the values of the individual segments
* change, as without it we get inconsistent behavior across screen readers.
*/
function initAnnouncer() {
if (!isBrowser)
return null;
let el = document.querySelector('[data-melt-announcer]');
if (!isHTMLElement(el)) {
const div = document.createElement('div');
div.style.cssText = styleToString({
border: '0px',
clip: 'rect(0px, 0px, 0px, 0px)',
'clip-path': 'inset(50%)',
height: '1px',
margin: '-1px',
overflow: 'hidden',
padding: '0px',
position: 'absolute',
'white-space': 'nowrap',
width: '1px',
});
div.setAttribute('data-melt-announcer', '');
div.appendChild(createLog('assertive'));
div.appendChild(createLog('polite'));
el = div;
document.body.insertBefore(el, document.body.firstChild);
}
/**
* Creates a log element for assertive or polite announcements.
*/
function createLog(kind) {
const log = document.createElement('div');
log.role = 'log';
log.ariaLive = kind;
log.setAttribute('aria-relevant', 'additions');
return log;
}
/**
* Retrieves the log element for assertive or polite announcements.
*/
function getLog(kind) {
if (!isHTMLElement(el))
return null;
const log = el.querySelector(`[aria-live="${kind}"]`);
if (!isHTMLElement(log))
return null;
return log;
}
return {
getLog,
};
}
/**
* Creates an announcer object that can be used to make `aria-live` announcements to screen readers.
*/
export function getAnnouncer() {
const announcer = initAnnouncer();
/**
* Announces a message to screen readers using the specified kind of announcement.
*/
function announce(value, kind = 'assertive', timeout = 7500) {
if (!announcer || !isBrowser)
return;
const log = announcer.getLog(kind);
const content = document.createElement('div');
if (typeof value === 'number') {
value = value.toString();
}
else if (value === null) {
value = 'Empty';
}
else {
value = value.trim();
}
content.innerText = value;
if (kind === 'assertive') {
log?.replaceChildren(content);
}
else {
log?.appendChild(content);
}
return setTimeout(() => {
content.remove();
}, timeout);
}
return {
announce,
};
}
|