UNPKG

@carbon/ibm-products

Version:
156 lines (154 loc) 6.17 kB
/** * Copyright IBM Corp. 2020, 2026 * * 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 { __toESM } from "../../_virtual/_rolldown/runtime.js"; import { require_classnames } from "../../node_modules/classnames/index.js"; import { pkg } from "../../settings.js"; import { prepareProps } from "../../global/js/utils/props-helper.js"; import { useResizeObserver } from "../../global/js/hooks/useResizeObserver.js"; import React, { useEffect, useRef, useState } from "react"; import PropTypes from "prop-types"; import { Button, ButtonSet, MenuButton, MenuItem, usePrefix } from "@carbon/react"; //#region src/components/ButtonSetWithOverflow/ButtonSetWithOverflow.jsx var import_classnames = /* @__PURE__ */ __toESM(require_classnames()); const blockClass = `${pkg.prefix}--button-set-with-overflow`; const componentName = "ButtonSetWithOverflow"; const buttonSize = "md"; const ButtonSetWithOverflow = ({ buttons, className, onWidthChange, buttonSetOverflowLabel, menuOptionsClass, rightAlign }) => { const carbonPrefix = usePrefix(); const [showAsOverflow, setShowAsOverflow] = useState(false); const spaceAvailableRef = useRef(null); const sizingContainerRefSet = useRef(null); const sizingContainerRefCombo = useRef(null); const sizes = 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; const sizingSet = sizingContainerRefSet.current?.querySelectorAll(`.${carbonPrefix}--btn`); let sizingSetTotalSize = 0; for (let item of sizingSet) sizingSetTotalSize += item.offsetWidth; const sizingComboSize = sizingContainerRefCombo.current?.offsetWidth; if (onWidthChange && (sizes.current.minWidth !== sizingComboSize || sizes.current.maxWidth !== sizingSetTotalSize)) { sizes.current.minWidth = sizingComboSize; sizes.current.maxWidth = sizingSetTotalSize; onWidthChange({ ...sizes.current }); } if (sizingSetTotalSize <= spaceAvailable) newShowAsOverflow = false; setShowAsOverflow(newShowAsOverflow); }; useEffect(() => { checkFullyVisibleItems(); }, [buttons]); const AButtonSet = React.forwardRef(({ isHidden = false, buttons, ...rest }, ref) => { return /* @__PURE__ */ React.createElement(ButtonSet, { ...rest, ref }, buttons.map(({ label, key, kind, id, ...other }) => { const kindFix = kind === "default" ? "primary" : kind; return /* @__PURE__ */ React.createElement(Button, { ...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: PropTypes.bool }; const AButtonMenu = React.forwardRef(({ buttons, ...rest }, ref) => { return /* @__PURE__ */ React.createElement(MenuButton, { ...rest, ref, label: buttonSetOverflowLabel }, buttons.map(({ key, kind, ...other }) => { const kindFix = kind === "danger" ? "danger" : "default"; return /* @__PURE__ */ React.createElement(MenuItem, { ...prepareProps(other, ["iconDescription", "renderIcon"]), key: key && `button-menu-${key}`, kind: kindFix }); }).reverse()); }); useResizeObserver(sizingContainerRefSet, checkFullyVisibleItems); useResizeObserver(sizingContainerRefCombo, checkFullyVisibleItems); useResizeObserver(spaceAvailableRef, checkFullyVisibleItems); return /* @__PURE__ */ React.createElement("div", { className: (0, import_classnames.default)([ 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, 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, size: buttonSize })), /* @__PURE__ */ React.createElement("div", { className: `${blockClass}__button-container ${blockClass}__button-container--visible` }, showAsOverflow ? /* @__PURE__ */ React.createElement(AButtonMenu, { buttons, size: buttonSize, className: menuOptionsClass }) : /* @__PURE__ */ React.createElement(AButtonSet, { className: `${blockClass}__button-container`, size: buttonSize, buttons }))); }; ButtonSetWithOverflow.propTypes = { /** * buttonSetOverflowLabel - used when button set is shown as combo button */ buttonSetOverflowLabel: PropTypes.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: PropTypes.array.isRequired, /** * className */ className: PropTypes.string, /** * class name applied to the overflow options */ menuOptionsClass: PropTypes.string, /** * onResize reports maxSize on resize */ onWidthChange: PropTypes.func, /** * align buttons to right of available space */ rightAlign: PropTypes.bool }; ButtonSetWithOverflow.displayName = componentName; //#endregion export { ButtonSetWithOverflow };