Skip to content

Instantly share code, notes, and snippets.

@johndavedecano
Created January 11, 2018 14:57
Show Gist options
  • Save johndavedecano/27a5279d2b456ab99c6bfa736722c28e to your computer and use it in GitHub Desktop.
Save johndavedecano/27a5279d2b456ab99c6bfa736722c28e to your computer and use it in GitHub Desktop.
mention.jsx
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