<commit_before>import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import ReactTransitionGroup from 'react-addons-transition-group';

const portal = {
    node: null,
    timer: null
};


class PopoverContent extends Component{


    componentWillAppear(callback) {
        portal.node.style.opacity = 1;
        console.log('will appear');
        callback();
    }

    componentWillEnter(callback){
        portal.node.style.opacity = 1;
        console.log('will enter');
        callback();
    }

    componentWillLeave(callback) {
        console.log('will leave');
        portal.node.style.opacity = 0;

        setTimeout(() => {
            callback();
            this.props.onMouseLeave();
            ReactDOM.unmountComponentAtNode(portal.node);
        }, 500);
    }

    render(){

        const { children, offset, onMouseEnter, onMouseLeave} = this.props;

        return (

            <div style={{}} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
                <div style={{ height: offset }}></div>
                {typeof children.type === 'function' ? React.cloneElement(children) : children}
            </div> 

        );

    }
}

class Popover extends Component {

    constructor(){
        super();
        this.state = {visible: true}
    }

    componentWillReceiveProps(props){
        this.setState({visible: true});

        if (!props.open) {
            portal.timer = setTimeout(() => {
                this.setState({visible: false});
            }, props.timeout);
        } else {
            clearInterval(portal.timer);
        }
                    
    }

    render() {
        const { children, ...other } = this.props;
        return ( 
        <ReactTransitionGroup>
            {this.state.visible ?
             <PopoverContent {...other}>{children}</PopoverContent> : null}
        </ReactTransitionGroup>
        );
    }
}

class Portal extends Component {

    static propTypes = {
        open: PropTypes.bool.isRequired,
        parent: PropTypes.string.isRequired,
        popoverClass: PropTypes.string,
        timeout: PropTypes.number,
        offset: PropTypes.number,
    }

    static defaultProps = {
        popoverClass: 'react-portal-popover__class',
        timeout: 500,
        offset: 0
    }

    componentWillReceiveProps(props) {
        const { open } = props;

        if (open == this.props.open) return;

        this.renderPortal(props);

    }

    componentDidMount() {

        if (!portal.node) {
            this.renderNode();
        }
    }


    renderNode() {
        portal.node = document.createElement('div');
        portal.node.className = this.props.popoverClass;

        // - Styles
        portal.node.style.transition = 'all 0.5s ease';
        portal.node.style.position = 'absolute';
        portal.node.style.opacity = 0;

        document.body.appendChild(portal.node);
    }

    updateNode() {

        const parent = document.querySelector(this.props.parent);

        const bounds = parent.getBoundingClientRect();
        const nodeBounds = portal.node.getBoundingClientRect();

        // - Calculate position of node 
        let top = bounds.top + bounds.height;
        let left = bounds.left + bounds.width / 2 - nodeBounds.width / 2;

        portal.node.style.top = top + 'px';
        portal.node.style.left = left + 'px';

    }

    renderPortal(props) {

        // - Delete any timer
        clearTimeout(portal.timer);

        // - Render portal 
        const {children, ...other} = props;

        ReactDOM.unstable_renderSubtreeIntoContainer(
            this,
            <Popover {...other}>{children}</Popover>,
            portal.node
        );

        this.updateNode();
    }

    shouldComponentUpdate(){
        return false;
    }

    render() {
        return null;
    }
}


export default Portal;<commit_msg>Cleanup and removed event listener on popover<commit_after>import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import ReactTransitionGroup from 'react-addons-transition-group';

const portal = {
    node: null,
    timer: null,
    active: false
};


/**
 * The popovercontent animates the popover and also renders it's children 
 * It is relied on ReactTransitionGroup for the animations.
 * The portal will be deleted after the animation is ended 
 */
class PopoverContent extends Component{

    addAnimation(){
        clearTimeout(portal.timer);
        portal.active = true;

        portal.node.classList.add(this.props.prefix + '__active');
        portal.node.classList.remove(this.props.prefix + '__hidden');
    }

    removeAnimation(){
        portal.node.classList.add(this.props.prefix + '__hidden');
        portal.node.classList.remove(this.props.prefix + '__active');
    }

    componentWillAppear(callback) {
        this.addAnimation();
        callback();
    }

    componentWillEnter(callback){
        this.addAnimation();
        callback();
    }

    componentWillLeave(callback) {
        clearTimeout(portal.timer);
        portal.timer = setTimeout(() => {

            this.removeAnimation();
            console.log('removing animation', portal.active);

            clearTimeout(portal.timer);
            if(portal.active) return callback();
            
            portal.timer = setTimeout(() =>{
                callback();
                portal.active = false;
            }, this.props.animationTime)

        }, this.props.timeout - this.props.animationTime);
    }

    render(){

        const { children, offset} = this.props;

        return (
            <div>
                <div style={{ height: offset }}></div>
                {typeof children.type === 'function' ? React.cloneElement(children) : children}
            </div> 
        );

    }
}

/**
 * The popover controls when the portal is removed 
 */
class Popover extends Component {

    constructor(){
        super();
        this.state = {hovered: false, visible: false }
    }

    componentWillMount(){
        this.setState({visible: this.props.open})
    }

    componentWillReceiveProps(props){
         this.setState({visible: props.open || this.state.hovered});
    }

    handleMouseEnter(){
        this.setState({hovered: true, visible: true});
    }

    handleMouseLeave(){
        this.setState({hovered: false, visible: false});
    }

    shouldComponentUpdate(){
        return true;
    }

    render() {

        const { children, ...other } = this.props;
        const visible = this.state.visible;
 
        return ( 
        <ReactTransitionGroup>
            {visible ? 
                    <PopoverContent {...other}>
                        <div onMouseEnter={this.handleMouseEnter.bind(this)} onMouseLeave={this.handleMouseLeave.bind(this)}>
                            {children}
                        </div>
                    </PopoverContent>
            : null}
        </ReactTransitionGroup>
        );
    }
}

class Portal extends Component {

    static propTypes = {
        open: PropTypes.bool.isRequired,
        parent: PropTypes.string.isRequired,
        prefix: PropTypes.string,
        timeout: PropTypes.number,
        offset: PropTypes.number,
        animationTime: PropTypes.number,
    }

    static defaultProps = {
        prefix: 'rpp',
        timeout: 3000,
        offset: 10,
        animationTime: 300,
    }

    componentWillReceiveProps(props) {
        const { open } = props;

        this.renderPortal(props);
    }


    componentDidMount() {
        if (!portal.node) {
            this.renderNode();
        }
    }


    renderNode() {
        
        portal.node = document.createElement('div');

        // - Styles
        portal.node.style.transition = `all 400ms ease`;
        portal.node.style.position = 'absolute';

        document.body.appendChild(portal.node);
    }

    updateNode() {

        const parent = document.querySelector(this.props.parent);

        const bounds = parent.getBoundingClientRect();
        const nodeBounds = portal.node.getBoundingClientRect();

        // - Calculate position of node 
        let top = bounds.top + bounds.height;
        let left = bounds.left;

        portal.node.style.top = top + 'px';
        portal.node.style.left = left + 'px';

    }

    renderPortal(props) {

        // - Render portal 
        const {children, ...other} = props;

        ReactDOM.unstable_renderSubtreeIntoContainer(
            this,
            <Popover {...other}>{children}</Popover>,
            portal.node
        );

        this.updateNode();
    }

    render() {
        return null;
    }
}


export default Portal;
{'fraction_non_alphanumeric': 0.11989414336670119, 'fraction_numerical': 0.0031066620642043494, 'mean_word_length': 1.9226630800268998, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7077082', 'n_tokens_mistral': 2416, 'n_tokens_neox': 2343, 'n_words': 481}