MinervaNeue/components/ToggleList/ToggleList.js

67 lines
2.0 KiB
JavaScript

( function () {
var
/** The component selector. */
selector = '.toggle-list',
/** The visible label icon associated with the checkbox. */
toggleSelector = '.toggle-list__toggle',
/** The underlying hidden checkbox that controls list visibility. */
checkboxSelector = '.toggle-list__checkbox';
/**
* Automatically dismiss the list when clicking or focusing elsewhere and update the
* aria-expanded attribute based on list visibility.
* @param {Window} window
* @param {HTMLElement} component
* @return {void}
*/
function bind( window, component ) {
var
toggle = component.querySelector( toggleSelector ),
checkbox = /** @type {HTMLInputElement} */ (
component.querySelector( checkboxSelector )
);
window.addEventListener( 'click', function ( event ) {
if ( event.target !== toggle && event.target !== checkbox ) {
// Something besides the button or checkbox was tapped. Dismiss the list.
_dismiss( checkbox );
}
}, true );
// If focus is given to any element outside the list, dismiss the list. Setting a focusout
// listener on list would be preferable, but this interferes with the click listener.
window.addEventListener( 'focusin', function ( event ) {
if ( event.target instanceof Node && !component.contains( event.target ) ) {
// Something besides the button or checkbox was focused. Dismiss the list.
_dismiss( checkbox );
}
}, true );
checkbox.addEventListener( 'change', _updateAriaExpanded.bind( undefined, checkbox ) );
}
/**
* Hides the list.
* @param {HTMLInputElement} checkbox
* @return {void}
*/
function _dismiss( checkbox ) {
checkbox.checked = false;
_updateAriaExpanded( checkbox );
}
/**
* Revise the aria-expanded state to match the checked state.
* @param {HTMLInputElement} checkbox
* @return {void}
*/
function _updateAriaExpanded( checkbox ) {
checkbox.setAttribute( 'aria-expanded', ( !!checkbox.checked ).toString() );
}
module.exports = Object.freeze( {
selector: selector,
bind: bind
} );
}() );