@carbon/react
Version:
React components for the Carbon Design System
183 lines (181 loc) • 5.83 kB
JavaScript
/**
* Copyright IBM Corp. 2016, 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 { usePrefix } from "../../internal/usePrefix.js";
import useIsomorphicEffect from "../../internal/useIsomorphicEffect.js";
import { useId } from "../../internal/useId.js";
import { deprecateValuesWithin } from "../../prop-types/deprecateValuesWithin.js";
import { mapPopoverAlign } from "../../tools/mapPopoverAlign.js";
import { useFeatureFlag } from "../FeatureFlags/index.js";
import { IconButton } from "../IconButton/index.js";
import Button_default from "../Button/index.js";
import { mergeRefs } from "../../tools/mergeRefs.js";
import { Menu as Menu$1 } from "../Menu/Menu.js";
import { useAttachedMenu } from "../../internal/useAttachedMenu.js";
import classNames from "classnames";
import React, { useRef } from "react";
import PropTypes from "prop-types";
import { jsx, jsxs } from "react/jsx-runtime";
import { ChevronDown } from "@carbon/icons-react";
import { autoUpdate, flip, hide, size, useFloating } from "@floating-ui/react";
//#region src/components/ComboButton/index.tsx
/**
* Copyright IBM Corp. 2023, 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.
*/
const defaultTranslations = { [{ "carbon.combo-button.additional-actions": "carbon.combo-button.additional-actions" }["carbon.combo-button.additional-actions"]]: "Additional actions" };
const defaultTranslateWithId = (messageId) => {
return defaultTranslations[messageId];
};
const ComboButton = React.forwardRef(function ComboButton({ children, className, disabled, label, onClick, size: size$1 = "lg", menuAlignment = "bottom", tooltipAlignment, translateWithId: t = defaultTranslateWithId, ...rest }, forwardRef) {
const enableOnlyFloatingStyles = useFeatureFlag("enable-v12-dynamic-floating-styles");
const id = useId("combobutton");
const prefix = usePrefix();
const containerRef = useRef(null);
let middlewares = [];
if (!enableOnlyFloatingStyles) middlewares = [flip({ crossAxis: false }), hide()];
if (menuAlignment === "bottom" || menuAlignment === "top") middlewares.push(size({ apply({ rects, elements }) {
Object.assign(elements.floating.style, { width: `${rects.reference.width}px` });
} }));
const { refs, floatingStyles, placement, middlewareData } = useFloating({
placement: menuAlignment,
strategy: "fixed",
middleware: middlewares,
whileElementsMounted: autoUpdate
});
const ref = mergeRefs(forwardRef, containerRef, refs.setReference);
const { open, handleClick: hookOnClick, handleMousedown: handleTriggerMousedown, handleClose } = useAttachedMenu(containerRef);
useIsomorphicEffect(() => {
const updatedFloatingStyles = {
...floatingStyles,
visibility: middlewareData.hide?.referenceHidden ? "hidden" : "visible"
};
Object.keys(updatedFloatingStyles).forEach((style) => {
if (refs.floating.current) refs.floating.current.style[style] = updatedFloatingStyles[style];
});
}, [
floatingStyles,
refs.floating,
middlewareData,
placement,
open
]);
function handleTriggerClick() {
if (containerRef.current) hookOnClick();
}
function handlePrimaryActionClick(e) {
if (onClick) onClick(e);
}
const containerClasses = classNames(`${prefix}--combo-button__container`, `${prefix}--combo-button__container--${size$1}`, { [`${prefix}--combo-button__container--open`]: open }, className);
const menuClasses = classNames(`${prefix}--combo-button__${menuAlignment}`);
const primaryActionClasses = classNames(`${prefix}--combo-button__primary-action`);
const triggerClasses = classNames(`${prefix}--combo-button__trigger`);
return /* @__PURE__ */ jsxs("div", {
...rest,
className: containerClasses,
ref,
"aria-owns": open ? id : void 0,
children: [
/* @__PURE__ */ jsx("div", {
className: primaryActionClasses,
children: /* @__PURE__ */ jsx(Button_default, {
title: label,
size: size$1,
disabled,
onClick: handlePrimaryActionClick,
children: label
})
}),
/* @__PURE__ */ jsx(IconButton, {
ref: refs.setReference,
className: triggerClasses,
label: t("carbon.combo-button.additional-actions"),
size: size$1,
disabled,
align: tooltipAlignment,
"aria-haspopup": true,
"aria-expanded": open,
onClick: handleTriggerClick,
onMouseDown: handleTriggerMousedown,
"aria-controls": open ? id : void 0,
children: /* @__PURE__ */ jsx(ChevronDown, {})
}),
/* @__PURE__ */ jsx(Menu$1, {
containerRef,
menuAlignment,
className: menuClasses,
ref: refs.setFloating,
id,
label: t("carbon.combo-button.additional-actions"),
size: size$1,
open,
onClose: handleClose,
children
})
]
});
});
ComboButton.propTypes = {
children: PropTypes.node.isRequired,
className: PropTypes.string,
disabled: PropTypes.bool,
label: PropTypes.string.isRequired,
menuAlignment: PropTypes.oneOf([
"top",
"top-start",
"top-end",
"bottom",
"bottom-start",
"bottom-end"
]),
onClick: PropTypes.func,
size: PropTypes.oneOf([
"xs",
"sm",
"md",
"lg"
]),
tooltipAlignment: deprecateValuesWithin(PropTypes.oneOf([
"top",
"top-left",
"top-right",
"bottom",
"bottom-left",
"bottom-right",
"left",
"left-bottom",
"left-top",
"right",
"right-bottom",
"right-top",
"top-start",
"top-end",
"bottom-start",
"bottom-end",
"left-end",
"left-start",
"right-end",
"right-start"
]), [
"top",
"top-start",
"top-end",
"bottom",
"bottom-start",
"bottom-end",
"left",
"left-start",
"left-end",
"right",
"right-start",
"right-end"
], mapPopoverAlign),
translateWithId: PropTypes.func
};
//#endregion
export { ComboButton };