text: /**
   * External dependencies
   */
  import classnames from 'classnames';
  import { partial, map, find, findIndex } from 'lodash';
  
  /**
   * WordPress dependencies
   */
  import { Component } from '@wordpress/element';
  import { NavigableMenu } from '@wordpress/components';
  import { withInstanceId, compose } from '@wordpress/compose';
  import isShallowEqual from '@wordpress/is-shallow-equal';
  
  /**
   * Internal dependencies
   */
  import { withPressedModifierKeys } from '@ithemes/security-hocs';
  import TabButton from './tab-button';
  
  class ControlledMultiTabPanel extends Component {
  	constructor() {
  		super( ...arguments );
  
  		this.handleClick = this.handleClick.bind( this );
  		this.onNavigate = this.onNavigate.bind( this );
  		this.onKeyDown = this.onKeyDown.bind( this );
  		this.toggleTab = this.toggleTab.bind( this );
  		this.getSelectedTabs = this.getSelectedTabs.bind( this );
  		this.isSelected = this.isSelected.bind( this );
  		this.getSelectedId = this.getSelectedId.bind( this );
  		this.getLabelledBy = this.getLabelledBy.bind( this );
  		this.getTabId = this.getTabId.bind( this );
  		this.getTabPanelId = this.getTabPanelId.bind( this );
  		this.isTabDisabled = this.isTabDisabled.bind( this );
  		this.isNonMultiSelectableTabSelected = this.isNonMultiSelectableTabSelected.bind( this );
  	}
  
  	handleClick( tabKey, event ) {
  		if ( event.metaKey || event.ctrlKey ) {
  			this.toggleTab( tabKey );
  		} else {
  			this.props.onSelect( [ tabKey ] );
  		}
  	}
  
  	onNavigate( childIndex, child ) {
  		const event = this.event;
  
  		if ( event ) {
  			if ( event.target.getAttribute( 'role' ) === 'tab' ) {
  				event.preventDefault();
  			}
  
  			if ( event.ctrlKey ) {
  				return;
  			}
  
  			if ( event.shiftKey ) {
  				if ( this.isTabDisabled( this.props.tabs[ childIndex ] ) ) {
  					return;
  				}
  
  				const name = this.props.tabs[ childIndex ].name;
  				this.toggleTab( name );
  
  				return;
  			}
  		}
  
  		child.click();
  	}
  
  	onKeyDown( event ) {
  		// onKeyDown is not omitted from the NavigableContainer GB-19694
  		if ( event.nativeEvent ) {
  			return;
  		}
  
  		// Stores the event for use in onNavigate. We don't need to persist the event
  		// since onNavigate is called during the original onKeyDown event handler.
  		this.event = event;
  
  		if ( event.ctrlKey && ( event.code === 'Space' || event.keyCode === 32 ) ) {
  			event.preventDefault();
  			const tabName = event.target.dataset.tabname;
  
  			if ( tabName ) {
  				this.toggleTab( tabName );
  			}
  		}
  	}
  
  	toggleTab( name ) {
  		const tab = find( this.props.tabs, { name } );
  
  		if ( tab && tab.allowMultiple === false ) {
  			return;
  		}
  
  		if ( this.props.selected.includes( name ) ) {
  			this.props.onSelect( this.props.selected.filter( ( maybeName ) => maybeName !== name ) );
  		} else {
  			this.props.onSelect( [
  				...this.props.selected,
  				name,
  			] );
  		}
  	}
  
  	getSelectedTabs() {
  		const selectedNames = this.props.selected;
  
  		if ( ! selectedNames.length && this.props.initialTab ) {
  			selectedNames.push( this.props.initialTab );
  		}
  
  		const tabs = [];
  
  		this.props.tabs.forEach( ( tab ) => {
  			if ( this.props.selected.includes( tab.name ) ) {
  				tabs.push( tab );
  			}
  		} );
  
  		return tabs;
  	}
  
  	isSelected( selectedTabs, maybeTab ) {
  		return selectedTabs.some( ( tab ) => tab.name === maybeTab.name );
  	}
  
  	isTabDisabled( tab ) {
  		const { pressedModifierKeys } = this.props;
  
  		if ( this.props.selected.includes( tab.name ) ) {
  			return false;
  		}
  
  		if ( tab.allowMultiple !== false && ! this.isNonMultiSelectableTabSelected() ) {
  			return false;
  		}
  
  		if ( pressedModifierKeys.meta || pressedModifierKeys.ctrl ) {
  			return true;
  		}
  
  		if ( pressedModifierKeys.shift ) {
  			const { activeElement } = document;
  
  			if ( activeElement.parentElement && activeElement.parentElement.id === `components-tab-panel__tabs-${ this.props.instanceId }` ) {
  				return true;
  			}
  		}
  
  		return false;
  	}
  
  	isNonMultiSelectableTabSelected() {
  		if ( this.props.selected.length !== 1 ) {
  			return false;
  		}
  
  		const selectedTab = find( this.props.tabs, { name: this.props.selected[ 0 ] } );
  
  		return selectedTab && selectedTab.allowMultiple === false;
  	}
  
  	getSelectedId( selectedTabs ) {
  		if ( selectedTabs.length === 1 ) {
  			return this.getTabPanelId( selectedTabs[ 0 ].name );
  		}
  
  		return `components-tab-panel__panel-${ this.props.instanceId }-${ map( selectedTabs, 'name' ).join( '-' ) }`;
  	}
  
  	getLabelledBy( selectedTabs ) {
  		return selectedTabs.map( ( tab ) => this.getTabId( tab.name ) ).join( ',' );
  	}
  
  	getTabId( tabName ) {
  		return `components-tab-panel__tab-${ this.props.instanceId }-${ tabName }`;
  	}
  
  	getTabPanelId( tabName ) {
  		return `components-tab-panel__panel-${ this.props.instanceId }-${ tabName }`;
  	}
  
  	componentDidUpdate( prevProps ) {
  		if ( this.props.selected.length !== 1 ) {
  			return;
  		}
  
  		if ( ! isShallowEqual( this.props.selected, prevProps.selected ) ) {
  			return;
  		}
  
  		const selected = this.props.selected[ 0 ];
  
  		if ( find( this.props.tabs, { name: selected } ) ) {
  			return;
  		}
  
  		const removedIndex = findIndex( prevProps.tabs, { name: selected } );
  
  		if ( removedIndex === -1 ) {
  			return;
  		}
  
  		const prevIndex = Math.max( removedIndex - 1, 0 );
  		const tab = this.props.tabs[ prevIndex ];
  
  		if ( tab ) {
  			this.props.onSelect( [ tab.name ] );
  		}
  	}
  
  	render() {
  		const {
  			tabs,
  			className,
  			activeClass = 'is-active',
  			orientation = 'horizontal',
  		} = this.props;
  
  		const selectedTabs = this.getSelectedTabs();
  		const selectedId = this.getSelectedId( selectedTabs );
  
  		return (
  			<div className={ className }>
  				<NavigableMenu
  					role="tablist"
  					aria-multiselectable
  					orientation={ orientation }
  					onNavigate={ this.onNavigate }
  					onKeyDown={ this.onKeyDown }
  					className="components-tab-panel__tabs"
  					id={ `components-tab-panel__tabs-${ this.props.instanceId }` }
  				>
  					{ tabs.map( ( tab ) => {
  						const isSelected = this.isSelected( selectedTabs, tab );
  						const controls = isSelected && selectedTabs.length > 1 ? selectedId : this.getTabPanelId( tab.name );
  
  						return (
  							<TabButton className={ classnames( tab.className, { [ activeClass ]: isSelected } ) }
  								tabId={ this.getTabId( tab.name ) }
  								aria-controls={ controls }
  								selected={ isSelected }
  								disabled={ this.isTabDisabled( tab ) }
  								key={ tab.name }
  								onClick={ partial( this.handleClick, tab.name ) }
  								data-tabname={ tab.name }
  							>
  								{ tab.title }
  							</TabButton>
  						);
  					} ) }
  				</NavigableMenu>
  				{ selectedTabs.length > 0 && (
  					<div aria-labelledby={ this.getLabelledBy( selectedTabs ) }
  						role="tabpanel"
  						id={ selectedId }
  						className="components-tab-panel__tab-content"
  						tabIndex="0"
  					>
  						{ this.props.children( selectedTabs ) }
  					</div>
  				) }
  			</div>
  		);
  	}
  }
  
  export default compose( [
  	withInstanceId,
  	withPressedModifierKeys,
  ] )( ControlledMultiTabPanel );
  