UNPKG

@mskcc/carbon-react

Version:

Carbon react components for the MSKCC DSM

145 lines (137 loc) 3.96 kB
/** * MSKCC 2021, 2024 */ import { extends as _extends } from '../../../_virtual/_rollupPluginBabelHelpers.js'; import cx from 'classnames'; import PropTypes from 'prop-types'; import React__default, { useRef, useState, useCallback, useMemo } from 'react'; import { useAttachedMenu } from '../../../internal/useAttachedMenu.js'; import { useId } from '../../../internal/useId.js'; import { Icon } from '../../Icon/MskIcon.js'; import { Menu } from '../../Menu/Menu.js'; const spacing = 0; /** * @component AvatarMenu component creates a menu button that feature's the user's avatar * @see https://react.carbondesignsystem.com/?path=/story/components-menu--playground */ function ControlMenuButton(_ref) { let { icon, buttonContent, children, className, disabled, menuClassName, target, label = '', onClose, onOpen, onKeyDown, ...rest } = _ref; const id = useId('ControlMenuButton'); const triggerRef = useRef(null); const menuRef = useRef(null); const [width, setWidth] = useState(0); const [position, setPosition] = useState('bottom'); const { open, x, y, handleClick, handleClose, handleMousedown } = useAttachedMenu(triggerRef); const doClose = useCallback(() => { handleClose(); onClose?.(); }, [onClose, handleClose]); const doClick = useCallback(() => { if (!triggerRef.current) { return; } const { width: w } = triggerRef.current.getBoundingClientRect(); setWidth(w); // TODO: this is a hack because onClose() not firing once handleMousedown() applied if (open) { doClose(); } handleClick(); }, [doClose, handleClick, open]); const doOpen = useCallback(() => { if (triggerRef.current && menuRef.current) { const { top: triggerTop, bottom: triggerBottom } = triggerRef.current.getBoundingClientRect(); const { top: menuTop, bottom: menuBottom } = menuRef.current.getBoundingClientRect(); if (triggerTop >= menuBottom && triggerTop > menuTop) { setPosition('top'); } else if (menuTop >= triggerBottom) { setPosition('bottom'); } else { setPosition(''); } // menuRef.current.style.width = `${width}px`; } onOpen?.(); }, [onOpen, menuRef, triggerRef]); const triggerClasses = useMemo(() => cx('msk-header--control-button', { active: open }), [open]); const parentClass = `msk-header--control-button-container ${className ?? ''}`.trim(); return /*#__PURE__*/React__default.createElement("div", _extends({}, rest, { ref: triggerRef, "aria-owns": open ? id : '', className: parentClass }), /*#__PURE__*/React__default.createElement("button", { type: "button", disabled: disabled, className: triggerClasses, "aria-haspopup": true, "aria-expanded": open, onClick: doClick, onMouseDown: () => handleMousedown, "aria-controls": open ? id : '' }, buttonContent ?? /*#__PURE__*/React__default.createElement(Icon, { icon: icon, className: "msk-header--control-button-icon" })), /*#__PURE__*/React__default.createElement(Menu, { className: cx('msk-header--control-button-menu', menuClassName), id: id, ref: menuRef, target: target, size: "lg", label: label, open: open, x: x, y: [y[0] - spacing, y[1] + spacing], onOpen: doOpen, onClose: doClose }, children)); } /** * The display name of the component. * */ ControlMenuButton.displayName = 'AvatarMenu'; ControlMenuButton.propTypes = { children: PropTypes.node, className: PropTypes.string, disabled: PropTypes.bool, id: PropTypes.string, label: PropTypes.string, level: PropTypes.number, onClose: PropTypes.func, onKeyDown: PropTypes.func, onOpen: PropTypes.func, open: PropTypes.bool, target: PropTypes.element, url: PropTypes.string }; export { ControlMenuButton };