Skip to content

Commit

Permalink
implement tooltip with content
Browse files Browse the repository at this point in the history
  • Loading branch information
nickmaltsev committed Nov 8, 2017
1 parent 45a4d06 commit 05ac4c8
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 1 deletion.
17 changes: 17 additions & 0 deletions demo/routes/tooltip/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import {
withTooltip,
withContentTooltip,
noop,
} from 'reactackle';
import {
Expand Down Expand Up @@ -48,6 +49,16 @@ SomeComponentTemplate.defaultProps = {
};
SomeComponentTemplate.displayName = 'SomeComponent';

const TooltipTarget = props =>
<div onClick={props.toggleTooltip}>{props.text}</div>;

const TooltipContent = props =>
<div
style={{ background: 'red', width: '100px', height: '100px'}}
>{props.tooltipText}</div>;

const C = withContentTooltip(TooltipTarget, TooltipContent);

export const SomeComponent = withTooltip(SomeComponentTemplate, true);

export const TooltipDemoRoute = () => (
Expand All @@ -57,6 +68,12 @@ export const TooltipDemoRoute = () => (
<TestBox>
<SomeComponent text="Tooltip" />
</TestBox>
<TestBox>
<C
text="New tooltip"
tooltipText="im tooltip text"
/>
</TestBox>
</DemoPreview>
<DemoCode
code={SnippetDefault}
Expand Down
3 changes: 2 additions & 1 deletion packages/reactackle-tooltip/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
],
"dependencies": {
"prop-types": "^15.5.10",
"react-portal": "^3.1.0"
"react-portal": "^3.1.0",
"reactackle-autoposition": "^0.0.3-beta.2"
},
"peerDependencies": {
"react": "^15.6.1",
Expand Down
1 change: 1 addition & 0 deletions packages/reactackle-tooltip/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ import Tooltip from './Tooltip';

export { Tooltip };
export * from './withTooltip';
export * from './withContentTooltip';
133 changes: 133 additions & 0 deletions packages/reactackle-tooltip/src/withContentTooltip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import React from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import { AutoPosition } from 'reactackle-autoposition';

const wrapWithClass = Component => {
const isFunctionalComponent = Component =>
!Component.prototype.render;
if (!isFunctionalComponent(Component)) return Component;
// eslint-disable-next-line react/prefer-stateless-function
return class ClassComponent extends React.Component {
render() {
return <Component {...this.props} />;
}
};
};

export const withContentTooltip = (Component, TooltipContent) => {
const propTypes = {
closeOnOutsideClick: PropTypes.bool,
};
const defaultProps = {
closeOnOutsideClick: true,
};
// eslint-disable-next-line react/no-multi-comp
class WithTooltip extends React.Component {
constructor(props) {
super(props);

this.state = {
targetRef: null,
contentRef: null,
visible: false,
};

this.TooltipTarget = wrapWithClass(Component);
this.TooltipContent = wrapWithClass(TooltipContent);

this._handleContentRef = this._handleContentRef.bind(this);
this._handleTargetRef = this._handleTargetRef.bind(this);
this._toggleTooltip = this._toggleTooltip.bind(this);
this._openTooltip = this._openTooltip.bind(this);
this._closeTooltip = this._closeTooltip.bind(this);
this._handleOutsideClick = this._handleOutsideClick.bind(this);
this._applyOutsideListener = this._applyOutsideListener.bind(this);
}

componentWillUnmount() {
document.removeEventListener('click', this._handleOutsideClick);
}

_handleTargetRef(ref) {
this.setState({ targetRef: ReactDOM.findDOMNode(ref) });
}

_handleContentRef(ref) {
this.setState({ contentRef: ReactDOM.findDOMNode(ref) });
}

_toggleTooltip() {
this.setState(({ visible }) => ({
visible: !visible,
}), this._applyOutsideListener);
}

_openTooltip() {
this.setState({ visible: true }, this._applyOutsideListener);
}

_closeTooltip() {
this.setState({ visible: false }, this._applyOutsideListener);
}

_applyOutsideListener() {
if (!this.props.closeOnOutsideClick) return;

if (this.state.visible) {
document.addEventListener('click', this._handleOutsideClick);
} else {
document.removeEventListener('click', this._handleOutsideClick);
}
}

_handleOutsideClick(e) {
if (!this.state.contentRef.contains(e.target)) {
this._closeTooltip();
}
}

render() {
const {
TooltipTarget,
TooltipContent,
} = this;

const tooltipProps = {
openTooltip: this._openTooltip,
closeTooltip: this._closeTooltip,
toggleTooltip: this._toggleTooltip,
};

const renderAutoPosition = !this.state.targetRef && !this.state.visible
? null
: <AutoPosition
parent={this.state.targetRef}
type="outer"
visible={this.state.visible}
>
<TooltipContent
{...this.props}
{...tooltipProps}
ref={this._handleContentRef}
/>
</AutoPosition>;

return (
<div>
<TooltipTarget
{...this.props}
{...tooltipProps}
ref={this._handleTargetRef}
/>
{renderAutoPosition}
</div>
);
}
}
WithTooltip.propTypes = propTypes;
WithTooltip.defaultProps = defaultProps;
WithTooltip.displayName = `withContentTooltip(${Component.displayName})`;

return WithTooltip;
};

0 comments on commit 05ac4c8

Please sign in to comment.