@carbon/react
Version:
React components for the Carbon Design System
135 lines (131 loc) • 4.13 kB
JavaScript
/**
* Copyright IBM Corp. 2016, 2023
*
* 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 { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
import React, { forwardRef, useRef, Children, isValidElement, cloneElement } from 'react';
import cx from 'classnames';
import { usePrefix } from '../../internal/usePrefix.js';
import { useMergedRefs } from '../../internal/useMergedRefs.js';
import PropTypes from 'prop-types';
import { AriaLabelPropType } from '../../prop-types/AriaPropTypes.js';
import './Content.js';
import './Header.js';
import './HeaderContainer.js';
import './HeaderGlobalAction.js';
import './HeaderGlobalBar.js';
import './HeaderMenu.js';
import './HeaderMenuButton.js';
import './HeaderMenuItem.js';
import './HeaderName.js';
import './HeaderNavigation.js';
import './HeaderPanel.js';
import './HeaderSideNavItems.js';
import SwitcherItem from './SwitcherItem.js';
import SwitcherDivider from './SwitcherDivider.js';
import './SkipToContent.js';
import './SideNav.js';
import './SideNavDetails.js';
import './SideNavDivider.js';
import './SideNavFooter.js';
import './SideNavHeader.js';
import './SideNavIcon.js';
import './SideNavItem.js';
import './SideNavItems.js';
import './SideNavLink.js';
import './SideNavLinkText.js';
import './SideNavMenu.js';
import './SideNavMenuItem.js';
import './SideNavSwitcher.js';
const Switcher = /*#__PURE__*/forwardRef(function Switcher(props, forwardRef) {
const switcherRef = useRef(null);
const ref = useMergedRefs([switcherRef, forwardRef]);
const prefix = usePrefix();
const {
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledBy,
className: customClassName,
children,
expanded
} = props;
const accessibilityLabel = {
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledBy
};
const className = cx(`${prefix}--switcher`, {
[customClassName || '']: !!customClassName
});
const handleSwitcherItemFocus = ({
currentIndex,
direction
}) => {
const enabledIndices = Children.toArray(children).reduce((acc, child, i) => {
if (/*#__PURE__*/isValidElement(child) && child.type === SwitcherItem && Object.keys(child.props).length) {
acc.push(i);
}
return acc;
}, []);
const nextValidIndex = (() => {
const nextIndex = enabledIndices.indexOf(currentIndex) + direction;
switch (enabledIndices[nextIndex]) {
case undefined:
if (direction === -1) {
return enabledIndices[enabledIndices.length - 1];
}
return enabledIndices[0];
case 0:
if (direction === 1) {
return enabledIndices[1];
}
default:
return enabledIndices[nextIndex];
}
})();
const switcherItem = switcherRef.current?.children[nextValidIndex]?.children[0];
if (switcherItem) {
switcherItem.focus();
}
};
const childrenWithProps = Children.toArray(children).map((child, index) => {
if (/*#__PURE__*/isValidElement(child) && child.type === SwitcherItem) {
return /*#__PURE__*/cloneElement(child, {
handleSwitcherItemFocus,
index,
key: index,
expanded
});
}
if (/*#__PURE__*/isValidElement(child) && child.type === SwitcherDivider) {
return /*#__PURE__*/cloneElement(child, {
key: index
});
}
return child;
});
return /*#__PURE__*/React.createElement("ul", _extends({
ref: ref,
className: className
}, accessibilityLabel), childrenWithProps);
});
Switcher.displayName = 'Switcher';
Switcher.propTypes = {
/**
* Required props for accessibility label on the underlying menu
*/
...AriaLabelPropType,
/**
* expects to receive <SwitcherItem />
*/
children: PropTypes.node.isRequired,
/**
* Optionally provide a custom class to apply to the underlying `<ul>` node
*/
className: PropTypes.string,
/**
* Specify whether the panel is expanded
*/
expanded: PropTypes.bool
};
export { Switcher as default };