Created
January 11, 2018 14:57
-
-
Save johndavedecano/27a5279d2b456ab99c6bfa736722c28e to your computer and use it in GitHub Desktop.
mention.jsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import Popper from 'popper.js'; | |
class RangeRef { | |
rect = {}; | |
constructor(rect) { | |
if (rect) { | |
this.rect = rect; | |
} | |
} | |
getBoundingClientRect() { | |
return this.rect; | |
} | |
get clientWidth() { | |
return this.rect.width; | |
} | |
get clientHeight() { | |
return this.rect.height; | |
} | |
} | |
export default class Suggestions extends Component { | |
rect = { | |
top: 0, | |
left: 0, | |
right: 0, | |
bottom: 0, | |
width: 0, | |
height: 0, | |
}; | |
/** | |
* Popup Element to used by popper | |
*/ | |
element = null; | |
/** | |
* PopperJS instance | |
*/ | |
popper = null; | |
/** | |
* Fake ref element | |
*/ | |
reference = new RangeRef(this.rect); | |
/** | |
* @property {Object} | |
*/ | |
static defaultProps = { | |
isOpen: false, | |
options: [], | |
}; | |
componentWillUnmount() { | |
this.popper && this.popper.destroy(); | |
this.popper = null; | |
} | |
componentDidMount() { | |
this.initializePopper(); | |
} | |
componentWillUpdate() { | |
this.popper && this.popper.update(); | |
} | |
getBoundingClientRect() { | |
let selection = document.getSelection(); | |
let range = selection && selection.rangeCount && selection.getRangeAt(0); | |
return range.getBoundingClientRect(); | |
} | |
initializePopper() { | |
this.reference = new RangeRef(this.rect); | |
this.popper = new Popper(this.reference, this.element, { | |
placement: 'bottom', | |
removeOnDestroy: true, | |
onUpdate: ({ instance }) => { | |
if (this.props.isOpen) { | |
this.reference = new RangeRef(this.getBoundingClientRect()); | |
this.element.style.display = 'block'; | |
} else { | |
this.element.style.display = 'none'; | |
instance.scheduleUpdate(); | |
} | |
}, | |
modifiers: { | |
offset: { offset: '0,5' }, | |
}, | |
}); | |
} | |
/** | |
* Handles active class name toggling. | |
* | |
* @param {Number} index | |
* | |
* @returns {String} | |
*/ | |
getClassName(index) { | |
return index === this.props.active ? 'active ' : ''; | |
} | |
/** | |
* Curry to onClick function in order to pass user object. | |
* | |
* @returns {Function} | |
*/ | |
onClick = (user, index) => { | |
const self = this; | |
return function(event) { | |
event.preventDefault(); | |
self.props.onSelect(event, user, index); | |
}; | |
}; | |
render() { | |
return ( | |
<div | |
ref={element => (this.element = element)} | |
className="Mention-suggestions" | |
> | |
<ul> | |
{this.props.options.map((user, index) => ( | |
<li key={user.id}> | |
<a | |
className={this.getClassName(index)} | |
href="/" | |
onClick={this.onClick(user, index)} | |
> | |
{user.label} | |
</a> | |
</li> | |
))} | |
</ul> | |
</div> | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment