grommet
Version:
focus on the essential experience
111 lines (108 loc) • 4.55 kB
JavaScript
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
import React, { Children, cloneElement, forwardRef, useEffect, useState } from 'react';
import { Box } from '../Box';
import { Drop } from '../Drop';
import { Keyboard } from '../Keyboard';
import { useForwardedRef, useKeyboard } from '../../utils';
import { TipPropTypes } from './propTypes';
import { useThemeValue } from '../../utils/useThemeValue';
/*
* This function getReactNodeRef is adapted from
* [Material UI] (https://github.com/mui/material-ui)
* Licensed under the MIT License (c) 2024 aarongarciah
* The function has been modified from its original version.
*/
var getReactNodeRef = function getReactNodeRef(element) {
if (!element || ! /*#__PURE__*/React.isValidElement(element)) {
return null;
}
// 'ref' is passed as prop in React 19, whereas 'ref' is directly attached to
// children in older versions
return {}.propertyIsEnumerable.call(element.props, 'ref') ? element.props.ref : element.ref;
};
var Tip = /*#__PURE__*/forwardRef(function (_ref, tipRef) {
var children = _ref.children,
content = _ref.content,
_ref$defaultVisible = _ref.defaultVisible,
defaultVisible = _ref$defaultVisible === void 0 ? false : _ref$defaultVisible,
dropProps = _ref.dropProps,
plain = _ref.plain;
var _useThemeValue = useThemeValue(),
theme = _useThemeValue.theme;
var _useState = useState(false),
over = _useState[0],
setOver = _useState[1];
var _useState2 = useState(false),
tooltipOver = _useState2[0],
setTooltipOver = _useState2[1];
var usingKeyboard = useKeyboard();
var componentRef = useForwardedRef(tipRef);
// Three use case for children
// 1. Tip has a single child + it is a React Element => Great!
// 2. Tip has a single child + not React Element =>
// span will wrap the child so we can use ref and events.
// 3. Tip has more than one child => Abort, display Children.only error
var child = Children.count(children) <= 1 && ! /*#__PURE__*/React.isValidElement(children) && /*#__PURE__*/React.createElement("span", null, children) || Children.only(children);
var clonedChild = /*#__PURE__*/cloneElement(child, {
onMouseEnter: function onMouseEnter(event) {
var _child$props;
setOver(true);
if ((_child$props = child.props) != null && _child$props.onMouseEnter) child.props.onMouseEnter(event);
},
onMouseLeave: function onMouseLeave(event) {
var _child$props2;
setOver(false);
if ((_child$props2 = child.props) != null && _child$props2.onMouseLeave) child.props.onMouseLeave(event);
},
onFocus: function onFocus(event) {
var _child$props3;
if (usingKeyboard) setOver(true);
if ((_child$props3 = child.props) != null && _child$props3.onFocus) child.props.onFocus(event);
},
onBlur: function onBlur(event) {
var _child$props4;
if (usingKeyboard) setOver(false);
if ((_child$props4 = child.props) != null && _child$props4.onBlur) child.props.onBlur(event);
},
key: 'tip-child',
ref: function ref(node) {
// https://github.com/facebook/react/issues/8873#issuecomment-287873307
if (typeof componentRef === 'function') {
componentRef(node);
} else if (componentRef) {
componentRef.current = node;
}
// Call the original ref, if any
var callerRef = getReactNodeRef(child);
if (typeof callerRef === 'function') {
callerRef(node);
} else if (callerRef) {
callerRef.current = node;
}
}
});
useEffect(function () {
setOver(defaultVisible);
}, [defaultVisible]);
return [clonedChild, (over || tooltipOver) && /*#__PURE__*/React.createElement(Keyboard, {
key: "tip-keyboard",
onEsc: function onEsc() {
setOver(false);
setTooltipOver(false);
}
}, /*#__PURE__*/React.createElement(Drop, _extends({
target: componentRef.current,
trapFocus: false,
key: "tip-drop"
}, theme.tip.drop, dropProps, {
onMouseEnter: function onMouseEnter() {
return setTooltipOver(true);
},
onMouseLeave: function onMouseLeave() {
return setTooltipOver(false);
}
}), plain ? content : /*#__PURE__*/React.createElement(Box, theme.tip.content, content)))];
});
Tip.displayName = 'Tip';
Tip.propTypes = TipPropTypes;
export { Tip };