|
import React from 'react'; |
|
import PropTypes from 'prop-types'; |
|
|
|
const eventHandler = /^on(?:[A-Z][a-z0-9]*)+$/; |
|
const eventSplitter = /(?=[A-Z])/; |
|
|
|
class Wrapper extends React.Component { |
|
static propTypes = { |
|
tag: PropTypes.string |
|
}; |
|
|
|
constructor (props) { |
|
super(props); |
|
this.customEventListeners = {}; |
|
} |
|
|
|
// life cycle methods |
|
|
|
componentDidMount () { |
|
let elem = document.createElement(this.props.tag); |
|
Object.keys(this.props). |
|
forEach(name => { this.setProp(elem, name, this.props[name]); }); |
|
this.parent.appendChild(elem); |
|
} |
|
|
|
componentWillUnmount () { |
|
Object.keys(this.customEventListeners). |
|
filter(name => this.customEventListeners.hasOwnProperty(name)). |
|
forEach(name => { this.parent.removeEventListener(name, this.customEventListeners[name]); }); |
|
this.customEventListeners = {}; |
|
} |
|
|
|
componentWillReceiveProps (nextProps) { |
|
let elem = this.parent.firstChild; |
|
if (elem) { |
|
// set changed attributes |
|
Object.keys(nextProps). |
|
forEach(name => { |
|
const value = nextProps[name]; |
|
if (!(name in this.props) || value !== this.props[name]) { |
|
this.setProp(elem, name, value); |
|
} |
|
}); |
|
// remove unused attributes |
|
Object.keys(this.props). |
|
filter(name => !(name in nextProps)). |
|
forEach(name => { |
|
this.setProp(elem, name, null); |
|
}); |
|
} |
|
} |
|
|
|
// own methods |
|
|
|
setProp (elem, name, value) { |
|
if (value === null) { |
|
if (eventHandler.test(name)) { |
|
let eventName = name.split(eventSplitter); |
|
eventName.shift(); |
|
eventName = eventName.map(part => part.toLowerCase()).join('-'); |
|
if (this.customEventListeners.hasOwnProperty(eventName)) { |
|
this.parent.removeEventListener(eventName, this.customEventListeners[eventName]); |
|
delete this.customEventListeners[eventName]; |
|
return; |
|
} |
|
} |
|
elem.removeAttribute(name); |
|
return; |
|
} |
|
if (typeof value == 'string') { |
|
elem.setAttribute(name, value); |
|
return; |
|
} |
|
if (typeof value == 'function' && eventHandler.test(name)) { |
|
let eventName = name.split(eventSplitter); |
|
eventName.shift(); |
|
eventName = eventName.map(part => part.toLowerCase()).join('-'); |
|
if (this.customEventListeners.hasOwnProperty(eventName)) { |
|
this.parent.removeEventListener(eventName, this.customEventListeners[eventName]); |
|
} |
|
this.customEventListeners[eventName] = value; |
|
this.parent.addEventListener(eventName, value); |
|
return; |
|
} |
|
elem[name] = value; |
|
} |
|
|
|
// render component |
|
|
|
render () { |
|
return <div ref={elem => { this.parent = elem; }}></div>; |
|
} |
|
} |
|
|
|
export default Wrapper; |