import React from 'react'
import ReactDOM from 'react-dom'
import { identity } from '../../func'
export interface BoundingClientRect {
width: number
height: number
left: number
right: number
top: number
bottom: number
}
interface Config {
debounceFunc: (func: () => void) => () => void
delay: number
}
const defaultConfig = {
debounceFunc: identity,
delay: 1000,
}
type WithClientRect
= P & { clientRect: BoundingClientRect }
function hocWithConfig
(Component: React.ComponentClass
| React.SFC
, config: Config) {
class Composed extends React.Component> {
static displayName = `withBoundingRect<${Component.displayName || Component.name || 'Unknown'}>`
state: BoundingClientRect = {
width: 0,
height: 0,
left: 0,
right: 0,
top: 0,
bottom: 0,
}
calcRect = config.debounceFunc(() => {
let node: Element = ReactDOM.findDOMNode(this) as Element
// ! to get correct client rect, have to remove all children
// then append them back after the calculation !
let children: any[] = []
while (node.firstChild) {
children.push(node.removeChild(node.firstChild!))
}
setTimeout(() => {
const rect = node.getBoundingClientRect()
children.forEach(e => node.appendChild(e))
this.setState({
width: rect.width,
height: rect.height,
left: rect.left,
right: rect.right,
top: rect.top,
bottom: rect.bottom,
})
}, config.delay)
})
componentDidMount() {
setTimeout(() => this.calcRect())
window.addEventListener('resize', this.calcRect)
window.addEventListener('resize-custom', this.calcRect)
}
componentWillUnmount() {
window.removeEventListener('resize', this.calcRect)
window.removeEventListener('resize-custom', this.calcRect)
}
render() {
return
}
}
return Composed as React.ComponentClass>
}
export function withBoundingRect(config: Partial = {}) {
return Component => hocWithConfig(Component, Object.assign({}, defaultConfig, config))
}