@appearhere/bloom
Version:
Appear Here's pattern library and styleguide
173 lines (156 loc) • 5.04 kB
JavaScript
/* eslint-disable react/no-multi-comp */
import PropTypes from 'prop-types';
import React, { Component, cloneElement } from 'react';
import cx from 'classnames';
import warning from 'warning';
import Tether, { HORIZONTAL_ATTACHMENTS, VERTICAL_ATTACHMENTS } from '../Tether/Tether';
import css from './Tooltip.css';
export { HORIZONTAL_ATTACHMENTS, VERTICAL_ATTACHMENTS } from '../Tether/Tether';
/* eslint-disable react/prefer-stateless-function */
class TetherDirectionWrapper extends Component {
render() {
const {
verticalAttachment,
horizontalAttachment,
verticalClassNames,
horizontalClassNames,
flushHorizontal,
flushVertical,
children,
className,
active,
...rest,
} = this.props;
const classNames = cx(
className,
verticalClassNames[verticalAttachment],
horizontalClassNames[horizontalAttachment],
flushVertical ? verticalClassNames.flushVertical : null,
flushHorizontal ? horizontalClassNames.flushHorizontal : null,
active ? css.active : null,
);
return (
<div className={ classNames }>
{ cloneElement(children, {
...rest,
verticalAttachment,
horizontalAttachment,
}) }
</div>
);
}
}
/* eslint-enable react/prefer-stateless-function */
TetherDirectionWrapper.propTypes = {
children: PropTypes.node,
verticalAttachment: PropTypes.oneOf(Object.keys(VERTICAL_ATTACHMENTS)),
horizontalAttachment: PropTypes.oneOf(Object.keys(HORIZONTAL_ATTACHMENTS)),
className: PropTypes.string,
verticalClassNames: PropTypes.shape({
[ ]: PropTypes.string,
[ ]: PropTypes.string,
[ ]: PropTypes.string,
}),
horizontalClassNames: PropTypes.shape({
[ ]: PropTypes.string,
[ ]: PropTypes.string,
[ ]: PropTypes.string,
}),
flushHorizontal: PropTypes.bool,
flushVertical: PropTypes.bool,
active: PropTypes.bool,
};
export default class Tooltip extends Component {
static propTypes = {
target: PropTypes.node,
children: PropTypes.node,
variant: PropTypes.oneOf(['light', 'dark']),
targetClassName: PropTypes.string,
className: PropTypes.string,
flushHorizontal: PropTypes.bool,
flushVertical: PropTypes.bool,
};
static defaultProps = {
variant: 'dark',
};
render() {
const {
target,
children,
variant,
flushHorizontal,
flushVertical,
className,
...rest,
} = this.props;
const targetClassNames = {
vertical: {
[ ]: css.targetVerticalCenter,
[ ]: css.targetTop,
[ ]: css.targetBottom,
flushVertical: css.targetFlushVertical,
},
horizontal: {
[ ]: css.targetHorizontalCenter,
[ ]: css.targetLeft,
[ ]: css.targetRight,
flushHorizontal: css.targetFlushHorizontal,
},
};
const tooltipClassNames = {
vertical: {
[ ]: css.tooltipVerticalCenter,
[ ]: css.tooltipTop,
[ ]: css.tooltipBottom,
flushVertical: css.tooltipFlushVertical,
},
horizontal: {
[ ]: css.tooltipHorizontalCenter,
[ ]: css.tooltipLeft,
[ ]: css.tooltipRight,
flushHorizontal: css.tooltipFlushHorizontal,
},
};
const targetClasses = cx(
css.target,
css[variant],
);
const tooltipClasses = cx(
css.tooltip,
css[variant],
className,
);
warning(
!(flushVertical && flushHorizontal),
'`Tooltip` component doesn\'t support the use of `flushVertical` and `flushHorizontal`' +
' in tandem. The tooltip will cover it\'s target and may cause unexpected behaviour'
);
return (
<Tether
{ ...rest }
flushVertical={ flushVertical }
flushHorizontal={ flushHorizontal }
target={ (
<TetherDirectionWrapper
ref={ (c) => { this.target = c; } }
className={ targetClasses }
verticalClassNames={ targetClassNames.vertical }
horizontalClassNames={ targetClassNames.horizontal }
>
{ target }
</TetherDirectionWrapper>
) }
>
<TetherDirectionWrapper
ref={ (c) => { this.tooltip = c; } }
className={ tooltipClasses }
verticalClassNames={ tooltipClassNames.vertical }
horizontalClassNames={ tooltipClassNames.horizontal }
>
{ children }
</TetherDirectionWrapper>
</Tether>
);
}
}
/* eslint-enable react/no-multi-comp */