main/Toggle.js

/**
 * Toggles visibility between two elements on the page.
 *
 * @example
 * <button class="toggle-switch">
 *	<span class="toggle-off">Initial State</span>
 *	<span class="toggle-on">Toggled State</span>
 * </button>
 *
 * @module Toggle
 */
const Toggle = {
	toggleSelector: '.toggle-switch',
	toggleOnSelector: '.toggle-on',
	toggleFlag: 'is-toggled',
	outsideClickListener: false,

	/**
	 * Binds click events to any `toggle-switch` blocks on the page.
	 * @method init
	 */
	init( $toggles ) {
		if ( ! $toggles ) {
			/* eslint-disable no-param-reassign */
			$toggles = document.querySelectorAll( this.toggleSelector );
			/* eslint-enable no-param-reassign */
		}
		[].forEach.call( $toggles, ( $toggle ) => {
			$toggle.addEventListener( 'click', () => {
				if ( $toggle.classList.contains( this.toggleFlag ) ) {
					$toggle.classList.remove( this.toggleFlag );
				} else {
					$toggle.classList.add( this.toggleFlag );

					const $toggleOn = $toggle.querySelector( this.toggleOnSelector );
					if ( $toggleOn && 'SELECT' === $toggleOn.nodeName ) {
						$toggleOn.focus();
						$toggleOn.addEventListener( 'blur', () => {
							$toggle.classList.remove( this.toggleFlag );
						});
					}

					// allow toggle element to collapse when user clicks outside of the element
					this.outsideClickListener = false;
					if ( $toggle.dataset.toggleOutsideClick ) {
						this.outsideClickListener = this.handleOutsideClick.bind( this, $toggle );
						document.addEventListener( 'click', this.outsideClickListener );
					}
				}
			});
		});
	},

	/**
	 * Handle clicks outside of a $toggle element
	 *
	 * @method handleOutsideClick
	 * @param $toggle - toggle element clicked
	 * @param evt - document click event
	 */
	handleOutsideClick( $toggle, evt ) {
		if ( evt.target
			&& ( ( evt.target === $toggle )
				|| ( evt.target.parentNode && evt.target.parentNode === $toggle ) ) ) {
			return;
		}

		$toggle.classList.remove( this.toggleFlag );
		document.removeEventListener( 'click', this.outsideClickListener );
	},
};

export default Toggle;