UNPKG

@carbon/react

Version:

React components for the Carbon Design System

112 lines (105 loc) 3.53 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, useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; import { usePrefix } from '../../internal/usePrefix.js'; import useIsomorphicEffect from '../../internal/useIsomorphicEffect.js'; const buttonOrder = kind => ({ ghost: 1, 'danger--ghost': 2, tertiary: 3, danger: 5, primary: 6 })[kind] ?? 4; const getButtonKind = element => { if (/*#__PURE__*/React.isValidElement(element) && element.props && typeof element.props === 'object') { const props = element.props; return props.kind ?? 'primary'; } return 'primary'; }; const ButtonSet = /*#__PURE__*/forwardRef((props, ref) => { const { children, className, fluid, stacked, ...rest } = props; const prefix = usePrefix(); const fluidInnerRef = useRef(null); const [isStacked, setIsStacked] = useState(false); const [sortedChildren, setSortedChildren] = useState(React.Children.toArray(children)); /** * Used to determine if the buttons are currently stacked */ useIsomorphicEffect(() => { const checkStacking = () => { let newIsStacked = stacked || false; if (fluidInnerRef && fluidInnerRef.current) { const computedStyle = window.getComputedStyle(fluidInnerRef.current); newIsStacked = computedStyle?.getPropertyValue?.('--flex-direction') === 'column'; } return newIsStacked; }; /* initial value not dependant on observer */ setIsStacked(checkStacking()); if (!fluidInnerRef.current) { return; } const resizeObserver = new ResizeObserver(() => { setIsStacked(checkStacking()); }); resizeObserver.observe(fluidInnerRef.current); return () => resizeObserver.disconnect(); }, [isStacked, stacked]); useEffect(() => { const newSortedChildren = React.Children.toArray(children); newSortedChildren.sort((a, b) => { return (buttonOrder(getButtonKind(a)) - buttonOrder(getButtonKind(b))) * (isStacked ? -1 : 1); }); setSortedChildren(newSortedChildren); // adding sortedChildren to deps causes an infinite loop }, [children, isStacked]); const buttonSetClasses = cx(className, `${prefix}--btn-set`, { [`${prefix}--btn-set--stacked`]: isStacked, [`${prefix}--btn-set--fluid`]: fluid }); return /*#__PURE__*/React.createElement("div", _extends({}, rest, { className: buttonSetClasses, ref: ref }), fluid ? /*#__PURE__*/React.createElement("div", { ref: fluidInnerRef, className: cx(`${prefix}--btn-set__fluid-inner`, { [`${prefix}--btn-set__fluid-inner--auto-stack`]: true }) }, sortedChildren) : children); }); ButtonSet.displayName = 'ButtonSet'; ButtonSet.propTypes = { /** * Specify the content of your ButtonSet */ children: PropTypes.node, /** * Specify an optional className to be added to your ButtonSet */ className: PropTypes.string, /** * fluid: button set resize to the size of the container up to a maximum dependant on the * number of buttons. */ fluid: PropTypes.bool, /** * Specify the button arrangement of the set (vertically stacked or * horizontal) - ignored when fluid is true */ stacked: PropTypes.bool }; export { ButtonSet as default };