UNPKG

@fluentui/react-northstar

Version:
256 lines (254 loc) 10.4 kB
import _invoke from "lodash/invoke"; import { tooltipAsLabelBehavior } from '@fluentui/accessibility'; import { useAccessibility, useAutoControlled, useTelemetry, useFluentContext, useTriggerElement, useUnhandledProps, useOnIFrameFocus } from '@fluentui/react-bindings'; import { Ref } from '@fluentui/react-component-ref'; import * as customPropTypes from '@fluentui/react-proptypes'; import * as PropTypes from 'prop-types'; import * as React from 'react'; import { commonPropTypes, isFromKeyboard, setWhatInputSource, getOrGenerateIdFromShorthand, createShorthandFactory } from '../../utils'; import { ALIGNMENTS, POSITIONS, Popper, AUTOSIZES } from '../../utils/positioner'; import { PortalInner } from '../Portal/PortalInner'; import { TooltipContent } from './TooltipContent'; export var tooltipClassName = 'ui-tooltip'; /** * A Tooltip displays additional non-modal information on top of its target element. * Tooltip doesn't receive focus and cannot contain focusable elements. * * @accessibility * Implements [ARIA Tooltip](https://www.w3.org/TR/wai-aria-practices-1.1/#tooltip) design pattern. */ export var Tooltip = /*#__PURE__*/function () { var Tooltip = function Tooltip(props) { var context = useFluentContext(); var _useTelemetry = useTelemetry(Tooltip.displayName, context.telemetry), setStart = _useTelemetry.setStart, setEnd = _useTelemetry.setEnd; setStart(); var accessibility = props.accessibility, align = props.align, content = props.content, flipBoundary = props.flipBoundary, mountNode = props.mountNode, mouseLeaveDelay = props.mouseLeaveDelay, offset = props.offset, overflowBoundary = props.overflowBoundary, pointing = props.pointing, popperRef = props.popperRef, position = props.position, positionFixed = props.positionFixed, target = props.target, trigger = props.trigger, unstable_disableTether = props.unstable_disableTether, unstable_pinned = props.unstable_pinned, autoSize = props.autoSize, subtle = props.subtle, dismissOnContentMouseEnter = props.dismissOnContentMouseEnter, mouseEnterDelay = props.mouseEnterDelay; var _useAutoControlled = useAutoControlled({ defaultValue: props.defaultOpen, value: props.open, initialValue: false }), open = _useAutoControlled[0], setOpen = _useAutoControlled[1]; var triggerElement = useTriggerElement(props); var unhandledProps = useUnhandledProps(Tooltip.handledProps, props); useOnIFrameFocus(open, context.target, function (e) { setOpen(function (__) { _invoke(props, 'onOpenChange', e, Object.assign({}, props, { open: false })); return false; }); }); var contentRef = React.useRef(); var pointerTargetRef = React.useRef(); var triggerRef = React.useRef(); var closeTimeoutId = React.useRef(); var openTimeoutId = React.useRef(); // TODO: Consider `getOrGenerateIdFromShorthand()` as hook and make it SSR safe var contentId = React.useRef(); contentId.current = getOrGenerateIdFromShorthand('tooltip-content-', content, contentId.current); var getA11Props = useAccessibility(accessibility, { actionHandlers: { close: function close(e) { setTooltipOpen(false, e); e.stopPropagation(); e.preventDefault(); } }, mapPropsToBehavior: function mapPropsToBehavior() { return { 'aria-describedby': props['aria-describedby'], 'aria-label': props['aria-label'], 'aria-labelledby': props['aria-labelledby'], contentId: contentId.current, triggerAriaLabel: trigger && trigger.props['aria-label'], open: open }; } }); var getContentOverrideProps = function getContentOverrideProps(predefinedProps) { return { onMouseEnter: function onMouseEnter(e) { if (!dismissOnContentMouseEnter) { setTooltipOpen(true, e); } _invoke(predefinedProps, 'onMouseEnter', e); }, onMouseLeave: function onMouseLeave(e) { setTooltipOpen(false, e); _invoke(predefinedProps, 'onMouseLeave', e); } }; }; var renderPopperChildren = function renderPopperChildren(popperProps) { var tooltipContent = TooltipContent.create(content, { defaultProps: function defaultProps() { return getA11Props('tooltip', { open: open, placement: popperProps.placement, pointing: pointing, pointerRef: pointerTargetRef, subtle: subtle }); }, generateKey: false, overrideProps: getContentOverrideProps }); return tooltipContent ? /*#__PURE__*/React.createElement(Ref, { innerRef: contentRef }, tooltipContent) : null; }; var shouldStayOpen = function shouldStayOpen(e) { return _invoke(e, 'currentTarget.contains', e.relatedTarget) || _invoke(contentRef.current, 'contains', e.relatedTarget); }; var trySetOpen = function trySetOpen(newValue, e) { setOpen(newValue); _invoke(props, 'onOpenChange', e, Object.assign({}, props, { open: newValue })); }; var setTooltipOpen = function setTooltipOpen(newOpen, e) { context.target.defaultView.clearTimeout(closeTimeoutId.current); context.target.defaultView.clearTimeout(openTimeoutId.current); if (newOpen) { if (mouseEnterDelay !== 0) { openTimeoutId.current = context.target.defaultView.setTimeout(function () { trySetOpen(true, e); }, mouseEnterDelay); } else { trySetOpen(true, e); } } else { closeTimeoutId.current = context.target.defaultView.setTimeout(function () { trySetOpen(false, e); }, mouseLeaveDelay); } }; var triggerProps = { onFocus: function onFocus(e) { if (isFromKeyboard()) { trySetOpen(true, e); } for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } _invoke.apply(void 0, [triggerElement, 'props.onFocus', e].concat(args)); }, onBlur: function onBlur(e) { if (!shouldStayOpen(e)) { trySetOpen(false, e); } for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { args[_key2 - 1] = arguments[_key2]; } _invoke.apply(void 0, [triggerElement, 'props.onBlur', e].concat(args)); }, onMouseEnter: function onMouseEnter(e) { setTooltipOpen(true, e); setWhatInputSource(context.target, 'mouse'); for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { args[_key3 - 1] = arguments[_key3]; } _invoke.apply(void 0, [triggerElement, 'props.onMouseEnter', e].concat(args)); }, onMouseLeave: function onMouseLeave(e) { setTooltipOpen(false, e); for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) { args[_key4 - 1] = arguments[_key4]; } _invoke.apply(void 0, [triggerElement, 'props.onMouseLeave', e].concat(args)); } }; var element = /*#__PURE__*/React.createElement(React.Fragment, null, triggerElement && /*#__PURE__*/React.createElement(Ref, { innerRef: triggerRef }, /*#__PURE__*/React.cloneElement(triggerElement, getA11Props('trigger', Object.assign({}, unhandledProps, triggerElement.props, triggerProps)))), /*#__PURE__*/React.createElement(PortalInner, { mountNode: mountNode }, /*#__PURE__*/React.createElement(Popper, { align: align, flipBoundary: flipBoundary, offset: offset, overflowBoundary: overflowBoundary, pointerTargetRef: pointerTargetRef, popperRef: popperRef, position: position, positionFixed: positionFixed, enabled: open, rtl: context.rtl, targetRef: target || triggerRef, children: renderPopperChildren, unstable_disableTether: unstable_disableTether, autoSize: autoSize, unstable_pinned: unstable_pinned }))); setEnd(); return element; }; Tooltip.displayName = 'Tooltip'; Tooltip.defaultProps = { align: 'center', position: 'above', mouseLeaveDelay: 10, mouseEnterDelay: 0, subtle: true, accessibility: tooltipAsLabelBehavior, offset: [4, 4] }; Tooltip.propTypes = Object.assign({}, commonPropTypes.createCommon({ as: false, content: false }), { dismissOnContentMouseEnter: PropTypes.bool, mouseEnterDelay: PropTypes.number, align: PropTypes.oneOf(ALIGNMENTS), subtle: PropTypes.bool, children: PropTypes.element, defaultOpen: PropTypes.bool, mountNode: customPropTypes.domNode, mouseLeaveDelay: PropTypes.number, offset: PropTypes.oneOfType([PropTypes.func, PropTypes.arrayOf(PropTypes.number)]), open: PropTypes.bool, onOpenChange: PropTypes.func, pointing: PropTypes.bool, position: PropTypes.oneOf(POSITIONS), positionFixed: PropTypes.bool, target: customPropTypes.domNode, trigger: customPropTypes.every([customPropTypes.disallow(['children']), PropTypes.element]), content: customPropTypes.shorthandAllowingChildren, unstable_disableTether: PropTypes.oneOf([true, false, 'all']), unstable_pinned: PropTypes.bool, autoSize: PropTypes.oneOf(AUTOSIZES), popperRef: customPropTypes.ref, flipBoundary: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object), PropTypes.oneOf(['clippingParents', 'window', 'scrollParent'])]), overflowBoundary: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object), PropTypes.oneOf(['clippingParents', 'window', 'scrollParent'])]) }); Tooltip.handledProps = Object.keys(Tooltip.propTypes); Tooltip.Content = TooltipContent; Tooltip.create = createShorthandFactory({ Component: Tooltip, mappedProp: 'content' }); return Tooltip; }(); //# sourceMappingURL=Tooltip.js.map