a11y_speak.js

import setAttributes from '../dom/set-attributes';

const el = {
	containers: [],
};
const state = {
	previousMessage: '',
};

/**
 * @ignore
 */
const addContainer = ( ariaLive = 'polite' ) => {
	const container = document.createElement( 'div' );
	setAttributes( container, {
		'aria-live': ariaLive,
		'aria-relevant': 'additions text',
		'aria-atomic': 'true',
		style: `position: absolute; margin: -1px; padding: 0; height: 1px; width: 1px; overflow: hidden; clip: rect(1px, 1px, 1px, 1px); -webkit-clip-path: inset(50%); clip-path: inset(50%); border: 0; word-wrap: normal !important;`,
	} );
	document.body.appendChild( container );
	el.containers.push( container );
};

/**
 * @ignore
 */
const filterMessage = ( message = '' ) => {
	let cleanedMessage = message.replace( /<[^<>]+>/g, ' ' );

	if ( state.previousMessage === cleanedMessage ) {
		cleanedMessage += '\u00A0';
	}

	state.previousMessage = cleanedMessage;

	return cleanedMessage;
};

/**
 * @ignore
 */
const clear = () => el.containers.forEach( ( container ) => container.textContent = '' );

/**
 * @ignore
 */
const setup = () => {
	if ( el.containers.length ) {
		return;
	}

	addContainer( 'assertive' );
	addContainer( 'polite' );
};

/**
 * @module speak
 * @description A shortened and custom variation of wp.a11y.speak that is lighter on the dom.
 *
 * @since 1.0.0
 *
 * @param {string} message  The message to announce.
 * @param {string} ariaLive The aria-live type attribute. Assertive or polite.
 *
 * @requires setAttributes
 *
 * @return {void}
 *
 * @example
 * import { speak } from "@gravityforms/utils";
 *
 * function Example() {
 *     speak( i18n.example, 'polite' );
 * }
 *
 */
export default function speak( message = '', ariaLive = 'polite' ) {
	setup();
	clear();

	const target = el.containers.filter( ( container ) => container.getAttribute( 'aria-live' ) === ariaLive )[ 0 ];
	if ( target ) {
		target.textContent = filterMessage( message );
	}
}