@appearhere/bloom
Version:
Appear Here's pattern library and styleguide
173 lines (156 loc) • 5.01 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 */