@mskcc/carbon-react
Version:
Carbon react components for the MSKCC DSM
181 lines (173 loc) • 6.45 kB
JavaScript
/**
* MSKCC 2021, 2024
*/
;
Object.defineProperty(exports, '__esModule', { value: true });
var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js');
var cx = require('classnames');
var PropTypes = require('prop-types');
var React = require('react');
var index = require('../Popover/index.js');
var useDelayedState = require('../../internal/useDelayedState.js');
var useId = require('../../internal/useId.js');
var useNoInteractiveChildren = require('../../internal/useNoInteractiveChildren.js');
var usePrefix = require('../../internal/usePrefix.js');
var match = require('../../internal/keyboard/match.js');
var keys = require('../../internal/keyboard/keys.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var cx__default = /*#__PURE__*/_interopDefaultLegacy(cx);
var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
function Tooltip(_ref) {
let {
align = 'top',
className: customClassName,
children,
label,
description,
enterDelayMs = 100,
leaveDelayMs = 300,
defaultOpen = false,
closeOnActivation = false,
disabled = false,
...rest
} = _ref;
const containerRef = React.useRef(null);
const tooltipRef = React.useRef(null);
const [open, setOpen] = useDelayedState.useDelayedState(defaultOpen);
const id = useId.useId('tooltip');
const prefix = usePrefix.usePrefix();
const child = React__default["default"].Children.only(children);
const triggerProps = disabled ? {} : {
onFocus: () => setOpen(true),
onBlur: () => setOpen(false),
onClick: () => closeOnActivation && setOpen(false),
onMouseEnter: onMouseEnter
};
function getChildEventHandlers(childProps) {
if (disabled) {
return {};
}
const eventHandlerFunctions = ['onFocus', 'onBlur', 'onClick', 'onMouseEnter'];
const eventHandlers = {};
eventHandlerFunctions.forEach(functionName => {
eventHandlers[functionName] = evt => {
triggerProps[functionName]();
if (childProps?.[functionName]) {
childProps?.[functionName](evt);
}
};
});
return eventHandlers;
}
if (label) {
triggerProps['aria-labelledby'] = id;
} else {
triggerProps['aria-describedby'] = id;
}
function onKeyDown(event) {
if (disabled) {
return;
}
if (open && match.match(event, keys.Escape)) {
event.stopPropagation();
setOpen(false);
}
if (open && closeOnActivation && (match.match(event, keys.Enter) || match.match(event, keys.Space))) {
setOpen(false);
}
}
function onMouseEnter() {
if (!disabled) {
setOpen(true, enterDelayMs);
}
}
function onMouseLeave() {
if (!disabled) {
setOpen(false, leaveDelayMs);
}
}
useNoInteractiveChildren.useNoInteractiveChildren(tooltipRef, 'The Tooltip component must have no interactive content rendered by the' + '`label` or `description` prop');
React.useEffect(() => {
if (containerRef !== null && containerRef.current) {
const interactiveContent = useNoInteractiveChildren.getInteractiveContent(containerRef.current);
if (!interactiveContent) {
setOpen(false);
}
}
});
return /*#__PURE__*/React__default["default"].createElement(index.Popover, _rollupPluginBabelHelpers["extends"]({}, rest, {
align: align,
className: cx__default["default"](`${prefix}--tooltip`, customClassName),
dropShadow: false,
highContrast: true,
onKeyDown: disabled ? undefined : onKeyDown,
onMouseLeave: disabled ? undefined : onMouseLeave,
open: disabled ? false : open,
ref: containerRef
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--tooltip-trigger__wrapper`
}, child !== undefined ? /*#__PURE__*/React__default["default"].cloneElement(child, {
...triggerProps,
...getChildEventHandlers(child.props)
}) : null), /*#__PURE__*/React__default["default"].createElement(index.PopoverContent, {
"aria-hidden": "true",
className: `${prefix}--tooltip-content`,
id: id,
ref: tooltipRef,
role: "tooltip"
}, label || description));
}
Tooltip.propTypes = {
/**
* Specify how the trigger should align with the tooltip
*/
align: PropTypes__default["default"].oneOf(['top', 'top-left', 'top-right', 'bottom', 'bottom-left', 'bottom-right', 'left', 'left-bottom', 'left-top', 'right', 'right-bottom', 'right-top']),
/**
* Pass in the child to which the tooltip will be applied
*/
children: PropTypes__default["default"].node,
/**
* Specify an optional className to be applied to the container node
*/
className: PropTypes__default["default"].string,
/**
* Determines wether the tooltip should close when inner content is activated (click, Enter or Space)
*/
closeOnActivation: PropTypes__default["default"].bool,
/**
* Specify whether the tooltip should be open when it first renders
*/
defaultOpen: PropTypes__default["default"].bool,
/**
* Provide the description to be rendered inside of the Tooltip. The
* description will use `aria-describedby` and will describe the child node
* in addition to the text rendered inside of the child. This means that if you
* have text in the child node, that it will be announced alongside the
* description to the screen reader.
*
* Note: if label and description are both provided, label will be used and
* description will not be used
*/
description: PropTypes__default["default"].node,
disabled: PropTypes__default["default"].bool,
/**
* Specify the duration in milliseconds to delay before displaying the tooltip
*/
enterDelayMs: PropTypes__default["default"].number,
/**
* Provide the label to be rendered inside of the Tooltip. The label will use
* `aria-labelledby` and will fully describe the child node that is provided.
* This means that if you have text in the child node, that it will not be
* announced to the screen reader.
*
* Note: if label and description are both provided, description will not be
* used
*/
label: PropTypes__default["default"].node,
/**
* Specify the duration in milliseconds to delay before hiding the tooltip
*/
leaveDelayMs: PropTypes__default["default"].number
};
exports.Tooltip = Tooltip;