UNPKG

@navinc/base-react-components

Version:
215 lines (203 loc) 6.36 kB
import React, { useState } from 'react' import MaterialTooltip from '@material-ui/core/Tooltip/index.js' import { makeStyles } from '@material-ui/core/styles/index.js' import styled from 'styled-components' import Icon from './icon.js' import { theme } from './theme.js' import PropTypes from 'prop-types' import isRebrand from './is-rebrand.js' const arrowGenerator = () => { return { '&[x-placement*="top"] $arrow': { bottom: 0, left: 0, marginBottom: '12px', marginTop: '12px', overflow: 'hidden', height: '12px', transition: 'none', transform: 'translateY(4px)', '&::before': { width: '12px', height: '12px', boxShadow: `1px 2px 4px 2px ${({ theme }) => (isRebrand(theme) ? theme.navNeutral300 : theme.neutral300)}`, transform: 'translate(15px, -6px) rotate(45deg)', }, }, '&[x-placement*="right"] $arrow': { left: 0, marginLeft: '12px', marginRight: '12px', width: '12px', overflow: 'hidden', transform: 'translateX(-10px)', transition: 'none', '&::before': { width: '12px', height: '12px', boxShadow: `1px 2px 4px 2px ${({ theme }) => (isRebrand(theme) ? theme.navNeutral300 : theme.neutral300)}`, transform: 'translate(6px, 12px) rotate(45deg)', }, }, } } const useStylesArrow = makeStyles(() => ({ arrow: { position: 'absolute', width: '42px', height: '42px', transition: 'none', '&::before': { content: '""', width: '12px', height: '12px', boxShadow: `1px 2px 4px 2px ${({ theme }) => (isRebrand(theme) ? theme.navNeutral300 : theme.neutral300)}`, backgroundColor: 'white', position: 'absolute', }, }, popper: arrowGenerator(), tooltip: { color: '#70727B', fontSize: '12px', lineHeight: '18px', backgroundColor: 'white', boxShadow: `1px 2px 4px 2px ${({ theme }) => (isRebrand(theme) ? theme.navNeutral300 : theme.neutral300)}`, width: '198px', marginBottom: '20px', }, })) const ArrowTooltip = ({ title, ...props }) => { const { arrow, ...classes } = useStylesArrow() const [arrowRef, setArrowRef] = useState(null) return ( <MaterialTooltip TransitionProps={{ timeout: 0 }} classes={classes} PopperProps={{ popperOptions: { modifiers: { arrow: { enabled: Boolean(arrowRef), element: arrowRef, }, }, }, }} {...props} title={ <> {title} <span className={arrow} ref={setArrowRef} /> </> } /> ) } const RightTooltip = styled(ArrowTooltip)` display: none; @media (${theme.forLargerThanPhone}) { display: inline-block; } ` const TopTooltip = styled(ArrowTooltip)` display: inline-block; @media (${theme.forLargerThanPhone}) { display: none; } ` const Wrapper = styled.span`` export const Tooltip = ({ children, className, iconName = 'actions/circle-info', disableFocusListener = false, disableHoverListener = false, disableTouchListener = false, enterDelay = 100, enterTouchDelay = 700, enterNextDelay = 0, interactive = false, leaveDelay = 0, leaveTouchDelay = 1500, onClose = () => {}, onOpen = () => {}, open, ...props }) => ( <Wrapper className={className}> <RightTooltip title={children} placement="right" disableFocusListener={disableFocusListener} disableHoverListener={disableHoverListener} disableTouchListener={disableTouchListener} enterDelay={enterDelay} enterTouchDelay={enterTouchDelay} enterNextDelay={enterNextDelay} interactive={interactive} leaveDelay={leaveDelay} leaveTouchDelay={leaveTouchDelay} onClose={onClose} onOpen={onOpen} open={open} > <div> <Icon name={iconName} {...props} /> </div> </RightTooltip> <TopTooltip title={children} placement="top" disableFocusListener={disableFocusListener} disableHoverListener={disableHoverListener} disableTouchListener={disableTouchListener} enterDelay={enterDelay} enterTouchDelay={enterTouchDelay} enterNextDelay={enterNextDelay} interactive={interactive} leaveDelay={leaveDelay} leaveTouchDelay={leaveTouchDelay} onClose={onClose} onOpen={onOpen} open={open} > <div> <Icon name={iconName} {...props} /> </div> </TopTooltip> </Wrapper> ) Tooltip.propTypes = { /** Add child components. */ children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]), /** Set the class names provided to Tooltip. */ className: PropTypes.string, /** Set the name of the icon to show (same as Icon component uses). */ iconName: PropTypes.string, /** Do not respond to focus events */ disableFocusListener: PropTypes.bool, /** Do not respond to hover events */ disableHoverListener: PropTypes.bool, /** Do not respond to long press touch events */ disableTouchListener: PropTypes.bool, /** The number of milliseconds to wait before showing the tooltip. This prop won't impact the enter touch delay (`enterTouchDelay`). */ enterDelay: PropTypes.number, /** The number of milliseconds a user must touch the element before showing the tooltip. */ enterTouchDelay: PropTypes.number, /** The number of milliseconds to wait before showing the tooltip when one was already recently opened. */ enterNextDelay: PropTypes.number, /** Makes a tooltip interactive, i.e. will not close when the user hovers over the tooltip before the `leaveDelay` is expired. */ interactive: PropTypes.bool, /** The number of milliseconds to wait before hiding the tooltip. This prop won't impact the leave touch delay (`leaveTouchDelay`). */ leaveDelay: PropTypes.number, /** The number of milliseconds after the user stops touching an element before hiding the tooltip. */ leaveTouchDelay: PropTypes.number, /** Callback fired when the component requests to be closed. */ onClose: PropTypes.func, /** Callback fired when the component requests to be open. */ onOpen: PropTypes.func, /** If `true`, the tooltip is shown. */ open: PropTypes.bool, } export default styled(Tooltip)``