UNPKG

apeman-react-mixins

Version:
112 lines (89 loc) 1.97 kB
/** * Mixin to detect outside tap. * @mixin ApOutsideMixin */ 'use strict' import React, {PropTypes as types} from 'react' import ReactDOM from 'react-dom' import defaults from 'defaults' class BodyTapRecognizer { constructor () { const s = this s._hammer = null } getDOMNode () { const s = this return document.body } getHammer () { const s = this let { _hammer } = s if (_hammer) { return _hammer } const Hammer = require('hammerjs') s._hammer = new Hammer(s.getDOMNode()) return s.getHammer() } addOutsideListener (listener) { const s = this, hammer = s.getHammer() hammer.on('tap', listener) } removeOutsideListener (listener) { const s = this, hammer = s.getHammer() hammer.off('tap', listener) } } Object.assign(BodyTapRecognizer, { singleton: new BodyTapRecognizer() }) /** @lends ApOutsideMixin */ let ApOutsideMixin = { // -------------------- // Custom // -------------------- $apOutsideMixed: true, statics: {}, handleTapForOutside(e) { const s = this, { props } = s, node = ReactDOM.findDOMNode(s) if (!node) { return } let contained = node.contains(e.target) if (!contained) { s.outsideDidTap(e) if (props.onOutside) { props.onOutside(e) } } }, // -------------------- // Specs // -------------------- propTypes: { onOutside: types.func }, // -------------------- // Lifecycle // -------------------- componentWillMount () { const s = this let noop = () => undefined defaults(s, { outsideDidTap: noop }) }, componentDidMount () { const s = this BodyTapRecognizer.singleton.addOutsideListener(s.handleTapForOutside) }, componentWillUnmount () { const s = this BodyTapRecognizer.singleton.removeOutsideListener(s.handleTapForOutside) } } export default Object.freeze(ApOutsideMixin)