UNPKG

@carbon/react

Version:

React components for the Carbon Design System

135 lines (131 loc) 4.13 kB
/** * 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 };