Skip to content

Commit

Permalink
Fix errors and update for react 16.6. Fix #81
Browse files Browse the repository at this point in the history
  • Loading branch information
romainberger committed Dec 18, 2018
1 parent b0ac079 commit 9c47675
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 74 deletions.
4 changes: 2 additions & 2 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
"babel-core": "^5.8.21",
"babel-loader": "^5.3.2",
"history": "^4.7.2",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react": "^16.6.3",
"react-dom": "^16.6.3",
"react-router": "3",
"superagent": "^1.8.3",
"webpack": "^1.11.0"
Expand Down
3 changes: 1 addition & 2 deletions example/src/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@ export default class Home extends Component {
Result:
<span className="btn btn-default" id="result" onMouseEnter={this.showTooltip} onMouseLeave={this.hideTooltip} style={{marginLeft: 10}}>Hover me!</span>
<ToolTip active={this.state.isTooltipActive} parent="#result" position={this.state.position} arrow={this.state.arrow} align={this.state.align} group="result">

{ this.state.isTooltipLoading ? 'Loading...' : <div>Tooltip content here</div>}
{ this.state.isTooltipLoading ? 'Loading...' : <div>Tooltip content here</div>}
</ToolTip>
</div>
</div>
Expand Down
40 changes: 29 additions & 11 deletions example/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1809,14 +1809,22 @@ promise@^7.1.1:
dependencies:
asap "~2.0.3"

prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.6.0:
prop-types@^15.5.4, prop-types@^15.5.6:
version "15.6.0"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856"
dependencies:
fbjs "^0.8.16"
loose-envify "^1.3.1"
object-assign "^4.1.1"

prop-types@^15.6.2:
version "15.6.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==
dependencies:
loose-envify "^1.3.1"
object-assign "^4.1.1"

proxy-addr@~2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec"
Expand Down Expand Up @@ -1908,14 +1916,15 @@ react-deep-force-update@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-2.1.1.tgz#8ea4263cd6455a050b37445b3f08fd839d86e909"

react-dom@^16.0.0:
version "16.0.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.0.0.tgz#9cc3079c3dcd70d4c6e01b84aab2a7e34c303f58"
react-dom@^16.6.3:
version "16.6.3"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.6.3.tgz#8fa7ba6883c85211b8da2d0efeffc9d3825cccc0"
integrity sha512-8ugJWRCWLGXy+7PmNh8WJz3g1TaTUt1XyoIcFN+x0Zbkoz+KKdUyx1AQLYJdbFXjuF41Nmjn5+j//rxvhFjgSQ==
dependencies:
fbjs "^0.8.16"
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.0"
prop-types "^15.6.2"
scheduler "^0.11.2"

react-hot-loader@next:
version "3.0.0-beta.7"
Expand Down Expand Up @@ -1946,14 +1955,15 @@ react-router@3:
prop-types "^15.5.6"
warning "^3.0.0"

react@^16.0.0:
version "16.0.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.0.0.tgz#ce7df8f1941b036f02b2cca9dbd0cb1f0e855e2d"
react@^16.6.3:
version "16.6.3"
resolved "https://registry.yarnpkg.com/react/-/react-16.6.3.tgz#25d77c91911d6bbdd23db41e70fb094cc1e0871c"
integrity sha512-zCvmH2vbEolgKxtqXL2wmGCUxUyNheYn/C+PD1YAjfxHC54+MhdruyhO7QieQrYsYeTxrn93PM2y0jRH1zEExw==
dependencies:
fbjs "^0.8.16"
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.0"
prop-types "^15.6.2"
scheduler "^0.11.2"

[email protected]:
version "1.0.27-1"
Expand Down Expand Up @@ -2149,6 +2159,14 @@ [email protected], safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"

scheduler@^0.11.2:
version "0.11.3"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.11.3.tgz#b5769b90cf8b1464f3f3cfcafe8e3cd7555a2d6b"
integrity sha512-i9X9VRRVZDd3xZw10NY5Z2cVMbdYg6gqFecfj79USv1CFN+YrJ3gIPRKf1qlY+Sxly4djoKdfx1T+m9dnRB8kQ==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"

semver@^5.3.0:
version "5.4.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@
"author": "Romain Berger <[email protected]>",
"license": "MIT",
"peerDependencies": {
"react": "^16.0.0",
"react-dom": "^16.0.0"
"react": "^16.6.0",
"react-dom": "^16.6.0"
},
"devDependencies": {
"babel": "^5.8.21",
"mocha": "^2.3.3",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react": "^16.6.0",
"react-dom": "^16.6.0",
"react-test-renderer": "^16.0.0"
}
}
124 changes: 83 additions & 41 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { Component } from 'react'
import React, { Component, Fragment } from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import ReactDOM, {unstable_renderSubtreeIntoContainer as renderSubtreeIntoContainer} from 'react-dom'

const FG_SIZE = 8
const BG_SIZE = 9
Expand Down Expand Up @@ -31,6 +31,7 @@ class Card extends Component {
style: PropTypes.object,
useHover: PropTypes.bool
}

static defaultProps = {
active: false,
position: 'right',
Expand All @@ -39,17 +40,23 @@ class Card extends Component {
style: {style: {}, arrowStyle: {}},
useHover: true
}

state = {
hover: false,
transition: 'opacity',
width: 0,
height: 0
height: 0,
}

margin = 15

defaultArrowStyle = {
color: '#fff',
borderColor: 'rgba(0,0,0,.4)'
}

rootRef = React.createRef()

getGlobalStyle() {
if (!this.props.parentEl) {
return {display: 'none'}
Expand All @@ -70,13 +77,15 @@ class Card extends Component {

return this.mergeStyle(style, this.props.style.style)
}

getBaseArrowStyle() {
return {
position: 'absolute',
content: '""',
transition: 'all .3s ease-in-out'
}
}

getArrowStyle() {
let fgStyle = this.getBaseArrowStyle()
let bgStyle = this.getBaseArrowStyle()
Expand Down Expand Up @@ -170,6 +179,7 @@ class Card extends Component {
bgStyle: this.mergeStyle(bgStyle, propsArrowStyle)
}
}

mergeStyle(style, theme) {
if (theme) {
let { position, top, left, right, bottom, marginLeft, marginRight, ...validTheme } = theme
Expand All @@ -182,10 +192,11 @@ class Card extends Component {

return style
}

getStyle(position, arrow) {
let alignOffset = 0;
let alignOffset = 0
let parent = this.props.parentEl
let align = this.props.align;
let align = this.props.align
let tooltipPosition = parent.getBoundingClientRect()
let scrollY = (window.scrollY !== undefined) ? window.scrollY : window.pageYOffset
let scrollX = (window.scrollX !== undefined) ? window.scrollX : window.pageXOffset
Expand All @@ -205,10 +216,10 @@ class Card extends Component {
}

if (align === 'left') {
alignOffset = - parentSize.width / 2 + FG_SIZE;
alignOffset = - parentSize.width / 2 + FG_SIZE
}
else if (align === 'right') {
alignOffset = parentSize.width / 2 - FG_SIZE;
alignOffset = parentSize.width / 2 - FG_SIZE
}

const stylesFromPosition = {
Expand Down Expand Up @@ -250,6 +261,7 @@ class Card extends Component {

return style
}

checkWindowPosition(style, arrowStyle) {
if (this.props.position === 'top' || this.props.position === 'bottom') {
if (style.left < 0) {
Expand Down Expand Up @@ -291,32 +303,46 @@ class Card extends Component {

return {style, arrowStyle}
}

handleMouseEnter = () => {
this.props.active && this.props.useHover && this.setState({hover: true})
}

handleMouseLeave = () => {
this.setState({hover: false})
}

static getDerivedStateFromProps(props, state) {
return {
transition: state.hover || props.active ? 'all' : 'opacity',
}
}

componentDidMount() {
this.updateSize()
}
componentWillReceiveProps() {
this.setState({transition: this.state.hover || this.props.active ? 'all' : 'opacity'}, () => {
this.updateSize()
})

componentDidUpdate() {
this.updateSize()
}

updateSize() {
let self = ReactDOM.findDOMNode(this)
this.setState({
width: self.offsetWidth,
height: self.offsetHeight
})
const newWidth = this.rootRef.current.offsetWidth
const newHeight = this.rootRef.current.offsetHeight

if (newWidth !== this.state.width || newHeight !== this.state.height) {
this.setState({
width: newWidth,
height: newHeight,
})
}
}

render() {
let {style, arrowStyle} = this.checkWindowPosition(this.getGlobalStyle(), this.getArrowStyle())

return (
<div style={style} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
<div style={style} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} ref={ this.rootRef }>
{this.props.arrow ? (
<div>
<span style={arrowStyle.fgStyle}/>
Expand All @@ -342,18 +368,39 @@ export default class ToolTip extends Component {
group: PropTypes.string,
tooltipTimeout: PropTypes.number
}

static defaultProps = {
active: false,
group: 'main',
tooltipTimeout: 500
}

createPortal() {
portalNodes[this.props.group] = {
node: document.createElement('div'),
timeout: false
}
portalNodes[this.props.group].node.className = 'ToolTipPortal'
document.body.appendChild(portalNodes[this.props.group].node)
}

renderPortal(props) {
if (!portalNodes[this.props.group]) {
this.createPortal()
}
let {parent, ...other} = props
let parentEl = typeof parent === 'string' ? document.querySelector(parent) : parent
ReactDOM.render(<Card parentEl={parentEl} {...other}/>, portalNodes[this.props.group].node)
}

componentDidMount() {
if (!this.props.active) {
return
}

this.renderPortal(this.props)
}

componentWillReceiveProps(nextProps) {
if ((!portalNodes[this.props.group] && !nextProps.active) ||
(!this.props.active && !nextProps.active)) {
Expand All @@ -377,32 +424,21 @@ export default class ToolTip extends Component {

this.renderPortal(newProps)
}

componentWillUnmount() {
if (portalNodes[this.props.group]) {
ReactDOM.unmountComponentAtNode(portalNodes[this.props.group].node)
clearTimeout(portalNodes[this.props.group].timeout)
document.body.removeChild(portalNodes[this.props.group].node);
}
}
createPortal() {
portalNodes[this.props.group] = {
node: document.createElement('div'),
timeout: false
}
portalNodes[this.props.group].node.className = 'ToolTipPortal'
document.body.appendChild(portalNodes[this.props.group].node)
}
renderPortal(props) {
if (!portalNodes[this.props.group]) {
this.createPortal()

try {
document.body.removeChild(portalNodes[this.props.group].node)
}
catch(e) {}

portalNodes[this.props.group] = null
}
let {parent, ...other} = props
let parentEl = typeof parent === 'string' ? document.querySelector(parent) : parent
renderSubtreeIntoContainer(this, <Card parentEl={parentEl} {...other}/>, portalNodes[this.props.group].node)
}
shouldComponentUpdate() {
return false
}

render() {
return null
}
Expand Down Expand Up @@ -443,9 +479,15 @@ export class StatefulToolTip extends Component {
...props
} = this.props

return [
<span className={ className } onMouseEnter={ this.onMouseEnter } onMouseLeave={ this.onMouseLeave } ref={ p => this.parent = p } key="parent">{ this.props.parent }</span>,
this.parent ? <ToolTip { ...props } active={ this.state.tooltipVisible } parent={ this.parent } key="tooltip">{ this.props.children }</ToolTip> : null,
]
return (
<Fragment>
<span className={ className } onMouseEnter={ this.onMouseEnter } onMouseLeave={ this.onMouseLeave } ref={ p => this.parent = p } key="parent">{ this.props.parent }</span>
{
this.parent ?
<ToolTip { ...props } active={ this.state.tooltipVisible } parent={ this.parent } key="tooltip">{ this.props.children }</ToolTip>
: null
}
</Fragment>
)
}
}
Loading

0 comments on commit 9c47675

Please sign in to comment.