@zendeskgarden/react-tooltips
Version:
Collection of components and render prop containers relating to Tooltips in the Garden Design System
315 lines (301 loc) • 11.1 kB
JavaScript
/**
* Copyright Zendesk, Inc.
*
* Use of this source code is governed under the Apache License, Version 2.0
* found at http://www.apache.org/licenses/LICENSE-2.0.
*/
'use strict';
var React = require('react');
var styled = require('styled-components');
var reactTheming = require('@zendeskgarden/react-theming');
var reactDom$1 = require('react-dom');
var PropTypes = require('prop-types');
var reactMergeRefs = require('react-merge-refs');
var containerTooltip = require('@zendeskgarden/container-tooltip');
var containerUtilities = require('@zendeskgarden/container-utilities');
var reactDom = require('@floating-ui/react-dom');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var React__default = /*#__PURE__*/_interopDefault(React);
var styled__default = /*#__PURE__*/_interopDefault(styled);
var PropTypes__default = /*#__PURE__*/_interopDefault(PropTypes);
const COMPONENT_ID$2 = 'tooltip.paragraph';
const StyledParagraph = styled__default.default.p.attrs({
'data-garden-id': COMPONENT_ID$2,
'data-garden-version': '9.11.3'
}).withConfig({
displayName: "StyledParagraph",
componentId: "sc-wuqkfc-0"
})(["margin:0;", ";"], reactTheming.componentStyles);
const COMPONENT_ID$1 = 'tooltip.title';
const StyledTitle = styled__default.default.strong.attrs({
'data-garden-id': COMPONENT_ID$1,
'data-garden-version': '9.11.3'
}).withConfig({
displayName: "StyledTitle",
componentId: "sc-vnjcvz-0"
})(["display:none;margin:0;font-weight:", ";", ";"], props => props.theme.fontWeights.semibold, reactTheming.componentStyles);
const COMPONENT_ID = 'tooltip.tooltip';
const sizeStyles = _ref => {
let {
theme,
$hasArrow,
$placement,
$size
} = _ref;
let margin = `${theme.space.base * 1.5}px`;
let borderRadius = theme.borderRadii.sm;
let padding = '0 1em';
let maxWidth;
let overflowWrap;
let whiteSpace = 'nowrap';
let lineHeight = reactTheming.getLineHeight(theme.space.base * 5, theme.fontSizes.sm);
let fontSize = theme.fontSizes.sm;
let titleDisplay;
let paragraphMarginTop;
let wordWrap;
if ($size !== 'small') {
borderRadius = theme.borderRadii.md;
overflowWrap = 'break-word';
whiteSpace = 'normal';
wordWrap = 'break-word';
}
if ($size === 'extra-large') {
padding = `${theme.space.base * 10}px`;
maxWidth = `460px`;
lineHeight = reactTheming.getLineHeight(theme.space.base * 5, theme.fontSizes.md);
paragraphMarginTop = `${theme.space.base * 2.5}px`;
} else if ($size === 'large') {
padding = `${theme.space.base * 5}px`;
maxWidth = `270px`;
lineHeight = reactTheming.getLineHeight(theme.space.base * 5, theme.fontSizes.md);
paragraphMarginTop = `${theme.space.base * 2}px`;
} else if ($size === 'medium') {
padding = '1em';
maxWidth = `140px`;
lineHeight = reactTheming.getLineHeight(theme.space.base * 4, theme.fontSizes.sm);
}
if ($size === 'extra-large' || $size === 'large') {
fontSize = theme.fontSizes.md;
titleDisplay = 'block';
}
let arrowSize;
let arrowShift;
if ($hasArrow) {
if ($size === 'small') {
arrowSize = margin;
if (['left-start', 'left-end', 'right-start', 'right-end'].includes($placement)) {
arrowShift = `-${theme.borderRadii.md}px`;
} else {
arrowShift = '0';
}
} else if ($size === 'medium') {
arrowSize = margin;
} else if ($size === 'large') {
margin = `${theme.space.base * 2}px`;
arrowSize = margin;
} else if ($size === 'extra-large') {
margin = `${theme.space.base * 3}px`;
arrowSize = `${theme.space.base * 2.5}px`;
}
}
return styled.css(["margin:", ";border-radius:", ";padding:", ";max-width:", ";line-height:", ";word-wrap:", ";white-space:", ";font-size:", ";overflow-wrap:", ";", ";", "{margin-top:", ";}", "{display:", ";}"], margin, borderRadius, padding, maxWidth, lineHeight, wordWrap, whiteSpace, fontSize, overflowWrap, $hasArrow && reactTheming.arrowStyles(reactTheming.getArrowPosition(theme, $placement), {
size: arrowSize,
shift: arrowShift
}), StyledParagraph, paragraphMarginTop, StyledTitle, titleDisplay);
};
const colorStyles = _ref2 => {
let {
theme,
$type
} = _ref2;
let borderColor;
let boxShadow;
let backgroundColor;
let color;
let titleColor;
if ($type === 'light') {
backgroundColor = reactTheming.getColor({
theme,
variable: 'background.raised'
});
borderColor = reactTheming.getColor({
theme,
variable: 'border.default'
});
boxShadow = theme.shadows.lg(`${theme.space.base * (theme.colors.base === 'dark' ? 4 : 5)}px`, `${theme.space.base * (theme.colors.base === 'dark' ? 6 : 7)}px`, reactTheming.getColor({
variable: 'shadow.medium',
theme
}));
color = reactTheming.getColor({
theme,
variable: 'foreground.subtle'
});
titleColor = reactTheming.getColor({
theme,
variable: 'foreground.default'
});
} else {
backgroundColor = reactTheming.getColor({
theme,
hue: 'neutralHue',
light: {
shade: 900
},
dark: {
shade: 700
}
});
borderColor = backgroundColor;
boxShadow = theme.shadows.lg(`${theme.space.base}px`, `${theme.space.base * 2}px`, reactTheming.getColor({
variable: 'shadow.small',
theme
}));
color = reactTheming.getColor({
theme,
hue: 'white'
});
}
return styled.css(["border-color:", ";box-shadow:", ";background-color:", ";color:", ";", "{color:", ";}"], borderColor, boxShadow, backgroundColor, color, StyledTitle, titleColor);
};
const StyledTooltip = styled__default.default.div.attrs({
'data-garden-id': COMPONENT_ID,
'data-garden-version': '9.11.3'
}).withConfig({
displayName: "StyledTooltip",
componentId: "sc-gzzjq4-0"
})(["display:inline-block;border:", ";box-sizing:border-box;direction:", ";text-align:", ";font-weight:", ";", ";&[aria-hidden='true']{display:none;}", ";", ";"], props => props.theme.borders.sm, props => props.theme.rtl && 'rtl', props => props.theme.rtl ? 'right' : 'left', props => props.theme.fontWeights.regular, sizeStyles, colorStyles, reactTheming.componentStyles);
const StyledTooltipWrapper = styled__default.default.div.withConfig({
displayName: "StyledTooltipWrapper",
componentId: "sc-1b7q9q6-0"
})(["position:absolute;top:0;left:0;transition:opacity 10ms;opacity:1;z-index:", ";&[aria-hidden='true']{visibility:hidden;opacity:0;}"], props => props.$zIndex);
const Paragraph = React.forwardRef((props, ref) => React__default.default.createElement(StyledParagraph, Object.assign({
ref: ref
}, props)));
Paragraph.displayName = 'Tooltip.Paragraph';
const Title = React.forwardRef((props, ref) => React__default.default.createElement(StyledTitle, Object.assign({
ref: ref
}, props)));
Title.displayName = 'Tooltip.Title';
const PLACEMENT = ['auto', ...reactTheming.PLACEMENT];
const SIZE = ['small', 'medium', 'large', 'extra-large'];
const TYPE = ['light', 'dark'];
const toSize = (size, type) => {
let retVal = size;
if (retVal === undefined) {
retVal = type === 'dark' ? 'small' : 'large';
}
return retVal;
};
const PLACEMENT_DEFAULT = 'top';
const TooltipComponent = _ref => {
let {
id,
delayMS = 500,
isInitialVisible,
content,
refKey = 'ref',
placement: _placement = PLACEMENT_DEFAULT,
fallbackPlacements: _fallbackPlacements,
children,
hasArrow = true,
size,
type = 'dark',
appendToNode,
zIndex,
isVisible: externalIsVisible,
onFocus,
onBlur,
...props
} = _ref;
const theme = React.useContext(styled.ThemeContext) || reactTheming.DEFAULT_THEME;
const triggerRef = React.useRef(null);
const floatingRef = React.useRef(null);
const {
isVisible,
getTooltipProps,
getTriggerProps,
openTooltip,
closeTooltip
} = containerTooltip.useTooltip({
id,
delayMilliseconds: delayMS,
isVisible: isInitialVisible,
triggerRef
});
const controlledIsVisible = containerUtilities.getControlledValue(externalIsVisible, isVisible);
const [floatingPlacement, fallbackPlacements] = reactTheming.getFloatingPlacements(theme, _placement === 'auto' ? PLACEMENT_DEFAULT : _placement, _fallbackPlacements);
const {
refs,
placement,
update,
floatingStyles: {
transform
}
} = reactDom.useFloating({
platform: {
...reactDom.platform,
isRTL: () => theme.rtl
},
elements: {
reference: triggerRef?.current,
floating: floatingRef?.current
},
placement: floatingPlacement,
middleware: _placement === 'auto' ? [reactDom.autoPlacement()] : [reactDom.flip({
fallbackPlacements
})]
});
React.useEffect(() => {
let cleanup;
if (controlledIsVisible && refs.reference.current && refs.floating.current) {
cleanup = reactDom.autoUpdate(refs.reference.current, refs.floating.current, update, {
elementResize: typeof ResizeObserver === 'function'
});
}
return () => cleanup && cleanup();
}, [controlledIsVisible, refs.reference, refs.floating, update]);
const Child = React__default.default.Children.only(children);
const Node = React__default.default.createElement(StyledTooltipWrapper, {
ref: floatingRef,
style: {
transform
},
$zIndex: zIndex,
"aria-hidden": !controlledIsVisible
}, React__default.default.createElement(StyledTooltip, Object.assign({
$hasArrow: hasArrow,
$placement: placement,
$size: toSize(size, type),
$type: type
}, getTooltipProps({
'aria-hidden': !controlledIsVisible,
onBlur: containerUtilities.composeEventHandlers(onBlur, () => closeTooltip(0)),
onFocus: containerUtilities.composeEventHandlers(onFocus, openTooltip),
...props
})), content));
return React__default.default.createElement(React__default.default.Fragment, null, React.cloneElement(Child, getTriggerProps({
...Child.props,
[refKey]: reactMergeRefs.mergeRefs([triggerRef, Child.ref ? Child.ref : null])
})), appendToNode ? reactDom$1.createPortal(Node, appendToNode) : Node);
};
TooltipComponent.displayName = 'Tooltip';
TooltipComponent.propTypes = {
appendToNode: PropTypes__default.default.any,
hasArrow: PropTypes__default.default.bool,
delayMS: PropTypes__default.default.number,
id: PropTypes__default.default.string,
content: PropTypes__default.default.node.isRequired,
placement: PropTypes__default.default.oneOf(PLACEMENT),
fallbackPlacements: PropTypes__default.default.arrayOf(PropTypes__default.default.oneOf(PLACEMENT.filter(placement => placement !== 'auto'))),
size: PropTypes__default.default.oneOf(SIZE),
type: PropTypes__default.default.oneOf(TYPE),
zIndex: PropTypes__default.default.oneOfType([PropTypes__default.default.number, PropTypes__default.default.string]),
isInitialVisible: PropTypes__default.default.bool,
refKey: PropTypes__default.default.string
};
const Tooltip = TooltipComponent;
Tooltip.Paragraph = Paragraph;
Tooltip.Title = Title;
exports.Paragraph = Paragraph;
exports.Title = Title;
exports.Tooltip = Tooltip;