UNPKG

@carbon/react

Version:

React components for the Carbon Design System

108 lines (104 loc) 3.31 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 } 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 SwitcherItem from './SwitcherItem.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 = React.Children.toArray(children).reduce((acc, curr, i) => { if (/*#__PURE__*/React.isValidElement(curr) && Object.keys(curr.props).length !== 0 && curr.type === SwitcherItem) { 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 = React.Children.toArray(children).map((child, index) => { // only setup click handlers if onChange event is passed if (/*#__PURE__*/React.isValidElement(child) && child.type === SwitcherItem) { return /*#__PURE__*/React.cloneElement(child, { handleSwitcherItemFocus, index, key: index, expanded }); } return /*#__PURE__*/React.cloneElement(child, { index, key: index, expanded }); }); 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 };