@mskcc/carbon-react
Version:
Carbon react components for the MSKCC DSM
145 lines (137 loc) • 3.96 kB
JavaScript
/**
* 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 };