carbon-components
Version:
The Carbon Design System is IBM’s open-source design system for products and experiences.
106 lines (99 loc) • 4.07 kB
JavaScript
/**
* Copyright IBM Corp. 2016, 2018
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
import mixin from '../../globals/js/misc/mixin';
import createComponent from '../../globals/js/mixins/create-component';
import initComponentByLauncher from '../../globals/js/mixins/init-component-by-launcher';
import eventedShowHideState from '../../globals/js/mixins/evented-show-hide-state';
import handles from '../../globals/js/mixins/handles';
import eventedState from '../../globals/js/mixins/evented-state';
import toggleAttribute from '../../globals/js/misc/toggle-attribute';
import settings from '../../globals/js/settings';
export default class NavigationMenuPanel extends mixin(
createComponent,
initComponentByLauncher,
eventedShowHideState,
handles,
eventedState
) {
createdByLauncher = (event) => {
const isExpanded = !this.element.hasAttribute('hidden');
const newState = isExpanded ? 'collapsed' : 'expanded';
this.triggerButton = event.delegateTarget;
this.changeState(newState);
};
/**
* Determine whether or not the state should change based on comparison with
* the current state
* @param {string} state
* @returns {boolean} true if given state is different from current state
*/
shouldStateBeChanged = (state) =>
(state === 'expanded') === this.element.hasAttribute('hidden');
/**
* Changes the expanded/collapsed state.
* @private
* @param {string} state The new state.
* @param {Function} callback Callback called when change in state completes.
*/
_changeState = (state, callback) => {
toggleAttribute(this.element, 'hidden', state !== 'expanded');
if (this.triggerButton) {
if (state === 'expanded') {
const focusableMenuItems = this.element.querySelector(
this.options.selectorFocusableMenuItem
);
if (focusableMenuItems) {
focusableMenuItems.focus();
}
}
const label =
state === 'expanded'
? this.triggerButton.getAttribute(this.options.attribLabelCollapse)
: this.triggerButton.getAttribute(this.options.attribLabelExpand);
this.triggerButton.classList.toggle(
this.options.classNavigationMenuPanelHeaderActionActive,
state === 'expanded'
);
this.triggerButton.setAttribute('aria-label', label);
this.triggerButton.setAttribute('title', label);
}
callback();
};
/**
* The map associating DOM element and NavigationMenuPanel instance.
* @member NavigationMenuPanel.components
* @type {WeakMap}
*/
static components /* #__PURE_CLASS_PROPERTY__ */ = new WeakMap();
/**
* The component options.
* If `options` is specified in the constructor,
* {@linkcode NavigationMenuPanel.create .create()}, or
* {@linkcode NavigationMenuPanel.init .init()},
* properties in this object are overridden for the instance being create and
* how {@linkcode NavigationMenuPanel.init .init()} works.
* @member NavigationMenuPanel.options
* @type {object}
* @property {string} selectorInit The CSS class to find popup navs.
* @property {string} attribInitTarget The attribute name in the launcher buttons to find target popup nav.
* @property {string[]} initEventNames The events that the component will handles
*/
static get options() {
const { prefix } = settings;
return {
initEventNames: ['click'],
eventBeforeExpanded: 'navigation-menu-being-expanded',
eventAfterExpanded: 'navigation-menu-expanded',
eventBeforeCollapsed: 'navigation-menu-being-collapsed',
eventAfterCollapsed: 'navigation-menu-collapsed',
selectorFocusableMenuItem: `.${prefix}--navigation__category-toggle, .${prefix}--navigation-link`,
classNavigationMenuPanelHeaderActionActive: `${prefix}--header__action--active`,
attribLabelExpand: 'data-navigation-menu-panel-label-expand',
attribLabelCollapse: 'data-navigation-menu-panel-label-collapse',
};
}
}