UNPKG

@carbon/ibm-products

Version:

Carbon for IBM Products

204 lines (193 loc) 7.15 kB
/** * Copyright IBM Corp. 2020, 2025 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ 'use strict'; var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js'); var React = require('react'); var index = require('../../_virtual/index.js'); var cx = require('classnames'); var useResizeObserver = require('../../global/js/hooks/useResizeObserver.js'); var react = require('@carbon/react'); var settings = require('../../settings.js'); var propsHelper = require('../../global/js/utils/props-helper.js'); const blockClass = `${settings.pkg.prefix}--button-set-with-overflow`; const componentName = 'ButtonSetWithOverflow'; const buttonSize = 'md'; const ButtonSetWithOverflow = _ref => { let { buttons, className, onWidthChange, buttonSetOverflowLabel, menuOptionsClass, rightAlign } = _ref; const carbonPrefix = react.usePrefix(); const [showAsOverflow, setShowAsOverflow] = React.useState(false); const spaceAvailableRef = React.useRef(null); const sizingContainerRefSet = React.useRef(null); const sizingContainerRefCombo = React.useRef(null); const sizes = React.useRef({}); /** * checkFullyVisibleItems determines display count based on space available and width of pageActions * * ButtonSetWithOverflow switches between a Carbon ButtonSet and use of the ButtonMenu component depending * on the space available. While there is sufficient space to show all of the buttons side by side the * ButtonSet is used, once this is no longer the case it switches to a ButtonMenu. * */ const checkFullyVisibleItems = () => { const spaceAvailable = spaceAvailableRef.current?.offsetWidth; let newShowAsOverflow = true; // get all of the hidden sizing buttons const sizingSet = sizingContainerRefSet.current?.querySelectorAll(`.${carbonPrefix}--btn`); // calculate total width of button set let sizingSetTotalSize = 0; for (let item of sizingSet) { sizingSetTotalSize += item.offsetWidth; } // check ButtonMenu size const sizingComboSize = sizingContainerRefCombo.current?.offsetWidth; if (onWidthChange && (sizes.current.minWidth !== sizingComboSize || sizes.current.maxWidth !== sizingSetTotalSize)) { sizes.current.minWidth = sizingComboSize; sizes.current.maxWidth = sizingSetTotalSize; // report min and max width required to host onWidthChange({ ...sizes.current }); } // only if space available use ButtonSet. if (sizingSetTotalSize <= spaceAvailable) { newShowAsOverflow = false; } setShowAsOverflow(newShowAsOverflow); }; React.useEffect(() => { checkFullyVisibleItems(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [buttons]); const AButtonSet = /*#__PURE__*/React.forwardRef((_ref2, ref) => { let { isHidden = false, buttons, ...rest } = _ref2; return /*#__PURE__*/React.createElement(react.ButtonSet, _rollupPluginBabelHelpers.extends({}, rest, { ref: ref }), buttons.map(_ref3 => { let { label, key, kind, id, ...other } = _ref3; const kindFix = kind === 'default' ? 'primary' : kind; return /*#__PURE__*/React.createElement(react.Button, _rollupPluginBabelHelpers.extends({}, other, { key: key && `button-set-${key}`, size: buttonSize, type: "button", kind: kindFix, id: id ? isHidden ? `${id}--hidden` : id : null }), label); })); }); AButtonSet.propTypes = { /** * isHidden - Used to conditionally change id if one is passed to the `AButtonSet` component * in order to avoid duplicate ids between the visible and hidden button set buttons */ isHidden: index.default.bool }; const AButtonMenu = /*#__PURE__*/React.forwardRef((_ref4, ref) => { let { buttons, ...rest } = _ref4; return /*#__PURE__*/React.createElement(react.MenuButton, _rollupPluginBabelHelpers.extends({}, rest, { ref: ref, label: buttonSetOverflowLabel }), buttons.map(_ref5 => { let { key, kind, ...other } = _ref5; // menu items only come in default and danger flavors const kindFix = kind === 'danger' ? 'danger' : 'default'; return /*#__PURE__*/React.createElement(react.MenuItem, _rollupPluginBabelHelpers.extends({}, propsHelper.prepareProps(other, ['iconDescription', 'renderIcon']), { key: key && `button-menu-${key}`, kind: kindFix })); }).reverse()); }); useResizeObserver.useResizeObserver(sizingContainerRefSet, checkFullyVisibleItems); useResizeObserver.useResizeObserver(sizingContainerRefCombo, checkFullyVisibleItems); useResizeObserver.useResizeObserver(spaceAvailableRef, checkFullyVisibleItems); return /*#__PURE__*/React.createElement("div", { className: cx([blockClass, className, { [`${blockClass}--right`]: rightAlign }]), ref: spaceAvailableRef }, /*#__PURE__*/React.createElement("div", { className: `${blockClass}__button-container ${blockClass}__button-container--hidden` }, /*#__PURE__*/React.createElement(AButtonSet, { "aria-hidden": true, ref: sizingContainerRefSet, size: buttonSize, buttons: buttons, isHidden: true })), /*#__PURE__*/React.createElement("div", { className: `${blockClass}__button-container ${blockClass}__button-container--hidden`, "aria-hidden": true }, /*#__PURE__*/React.createElement(AButtonMenu, { className: menuOptionsClass, ref: sizingContainerRefCombo, buttons: buttons, size: buttonSize })), /*#__PURE__*/React.createElement("div", { className: `${blockClass}__button-container ${blockClass}__button-container--visible` }, showAsOverflow ? /*#__PURE__*/React.createElement(AButtonMenu, { buttons: buttons, size: buttonSize, className: menuOptionsClass }) : /*#__PURE__*/React.createElement(AButtonSet, { className: `${blockClass}__button-container`, size: buttonSize, buttons: buttons }))); }; ButtonSetWithOverflow.propTypes = { /** * buttonSetOverflowLabel - used when button set is shown as combo button */ buttonSetOverflowLabel: index.default.node.isRequired, /** * Specifies the buttons for the ButtonSetWithOverflow. Each item is specified as an object * with the properties of a Carbon Button plus a label. * * Carbon Button API https://react.carbondesignsystem.com/?path=/docs/components-button--default#component-api */ buttons: index.default.array.isRequired, /** * className */ className: index.default.string, /** * class name applied to the overflow options */ menuOptionsClass: index.default.string, /** * onResize reports maxSize on resize */ onWidthChange: index.default.func, /** * align buttons to right of available space */ rightAlign: index.default.bool }; ButtonSetWithOverflow.displayName = componentName; exports.ButtonSetWithOverflow = ButtonSetWithOverflow;