UNPKG

@mskcc/carbon-react

Version:

Carbon react components for the MSKCC DSM

255 lines (249 loc) 7.43 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, useContext } from 'react'; import { Popover, PopoverContent } from '../Popover/index.js'; import { useWindowEvent } from '../../internal/useEvent.js'; import { useId } from '../../internal/useId.js'; import { usePrefix } from '../../internal/usePrefix.js'; import { match } from '../../internal/keyboard/match.js'; import { Escape } from '../../internal/keyboard/keys.js'; /** * Used to render the label for a Toggletip */ function ToggletipLabel(_ref) { let { as: BaseComponent = 'span', children, className: customClassName } = _ref; const prefix = usePrefix(); const className = cx(`${prefix}--toggletip-label`, customClassName); const BaseComponentAsAny = BaseComponent; return /*#__PURE__*/React__default.createElement(BaseComponentAsAny, { className: className }, children); } ToggletipLabel.propTypes = { /** * Provide a custom element or component to render the top-level node for the * component. */ as: PropTypes.elementType, /** * Custom children to be rendered as the content of the label */ children: PropTypes.node, /** * Provide a custom class name to be added to the outermost node in the * component */ className: PropTypes.string }; // Used to coordinate accessibility props between button and content along with // the actions to open and close the toggletip const ToggletipContext = /*#__PURE__*/React__default.createContext(undefined); function useToggletip() { return useContext(ToggletipContext); } /** * Used as a container for the button and content of a toggletip. This component * is responsible for coordinating between interactions with the button and the * visibility of the content */ function Toggletip(_ref2) { let { align, as, className: customClassName, children, defaultOpen = false } = _ref2; const ref = useRef(null); const [open, setOpen] = useState(defaultOpen); const prefix = usePrefix(); const id = useId(); const className = cx(`${prefix}--toggletip`, customClassName, { [`${prefix}--toggletip--open`]: open }); const actions = { toggle: () => { setOpen(!open); }, close: () => { setOpen(false); } }; const value = { buttonProps: { 'aria-expanded': open, 'aria-controls': id, onClick: actions.toggle }, contentProps: { id } }; const onKeyDown = event => { if (open && match(event, Escape)) { actions.close(); // If the menu is closed while focus is still inside the menu, it should return to the trigger button (#12922) const button = ref.current?.children[0]; if (button instanceof HTMLButtonElement) { button.focus(); } } }; const handleBlur = event => { // Do not close if the menu itself is clicked, should only close on focus out if (open && event.relatedTarget === null) { return; } if (!event.currentTarget.contains(event.relatedTarget)) { // The menu should be closed when focus leaves the `Toggletip` (#12922) actions.close(); } }; // If the `Toggletip` is the last focusable item in the tab order, it shoudl also close when the browser window loses focus (#12922) useWindowEvent('blur', () => { if (open) { actions.close(); } }); useWindowEvent('click', event => { if (open && ref.current && !ref.current.contains(event.target)) { actions.close(); } }); return /*#__PURE__*/React__default.createElement(ToggletipContext.Provider, { value: value }, /*#__PURE__*/React__default.createElement(Popover, { align: align, as: as, caret: true, className: className, dropShadow: false, highContrast: true, open: open, onKeyDown: onKeyDown, onBlur: handleBlur, ref: ref }, children)); } Toggletip.propTypes = { /** * Specify how the toggletip should align with the button */ align: PropTypes.oneOf(['top', 'top-left', 'top-right', 'bottom', 'bottom-left', 'bottom-right', 'left', 'left-bottom', 'left-top', 'right', 'right-bottom', 'right-top']), /** * Provide a custom element or component to render the top-level node for the * component. */ as: PropTypes.elementType, /** * Custom children to be rendered as the content of the label */ children: PropTypes.node, /** * Provide a custom class name to be added to the outermost node in the * component */ className: PropTypes.string, /** * Specify if the toggletip should be open by default */ defaultOpen: PropTypes.bool }; /** * `ToggletipButton` controls the visibility of the Toggletip through mouse * clicks and keyboard interactions. */ function ToggletipButton(_ref3) { let { children, className: customClassName, label = 'Show information' } = _ref3; const toggletip = useToggletip(); const prefix = usePrefix(); const className = cx(`${prefix}--toggletip-button`, customClassName); return /*#__PURE__*/React__default.createElement("button", _extends({}, toggletip?.buttonProps, { "aria-label": label, type: "button", className: className }), children); } ToggletipButton.propTypes = { /** * Custom children to be rendered as the content of the label */ children: PropTypes.node, /** * Provide a custom class name to be added to the outermost node in the * component */ className: PropTypes.string, /** * Provide an accessible label for this button */ label: PropTypes.string }; /** * `ToggletipContent` is a wrapper around `PopoverContent`. It places the * `children` passed in as a prop inside of `PopoverContent` so that they will * be rendered inside of the popover for this component. */ function ToggletipContent(_ref4) { let { children, className: customClassName } = _ref4; const toggletip = useToggletip(); const prefix = usePrefix(); return /*#__PURE__*/React__default.createElement(PopoverContent, _extends({ className: customClassName }, toggletip?.contentProps), /*#__PURE__*/React__default.createElement("div", { className: `${prefix}--toggletip-content` }, children)); } ToggletipContent.propTypes = { /** * Custom children to be rendered as the content of the label */ children: PropTypes.node, /** * Provide a custom class name to be added to the outermost node in the * component */ className: PropTypes.string }; /** * `ToggletipActions` is a container for one or two actions present at the base * of a toggletip. It is used for layout of these items. */ function ToggletipActions(_ref5) { let { children, className: customClassName } = _ref5; const prefix = usePrefix(); const className = cx(`${prefix}--toggletip-actions`, customClassName); return /*#__PURE__*/React__default.createElement("div", { className: className }, children); } ToggletipActions.propTypes = { /** * Custom children to be rendered as the content of the label */ children: PropTypes.node, /** * Provide a custom class name to be added to the outermost node in the * component */ className: PropTypes.string }; export { Toggletip, ToggletipActions, ToggletipButton, ToggletipContent, ToggletipLabel };