Skip to content

Instantly share code, notes, and snippets.

@rdela
Forked from necolas/Hoverable.js
Created March 5, 2018 20:38
Show Gist options
  • Save rdela/60fb8a676d5b78cfede396297d4f8f15 to your computer and use it in GitHub Desktop.
Save rdela/60fb8a676d5b78cfede396297d4f8f15 to your computer and use it in GitHub Desktop.

Revisions

  1. @necolas necolas revised this gist Jan 27, 2018. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions Hoverable.js
    Original file line number Diff line number Diff line change
    @@ -9,6 +9,9 @@ const hover = createHoverMonitor();
    * <Hoverable>
    * {(hover) => <View style={hover && styles.hovered} />}
    * </Hoverable>
    *
    * Example: https://imaginary-lycra.glitch.me/
    * Example source: https://glitch.com/edit/#!/imaginary-lycra
    */
    class Hoverable extends Component {
    static displayName = 'Hoverable';
  2. @necolas necolas revised this gist Jan 26, 2018. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions Hoverable.js
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,12 @@ import React, { Component } from 'react';

    const hover = createHoverMonitor();

    /**
    * Use:
    * <Hoverable>
    * {(hover) => <View style={hover && styles.hovered} />}
    * </Hoverable>
    */
    class Hoverable extends Component {
    static displayName = 'Hoverable';

  3. @necolas necolas created this gist Jan 26, 2018.
    56 changes: 56 additions & 0 deletions Hoverable.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,56 @@
    import createHoverMonitor from './createHoverMonitor';
    import { element, func, oneOfType } from 'prop-types';
    import React, { Component } from 'react';

    const hover = createHoverMonitor();

    class Hoverable extends Component {
    static displayName = 'Hoverable';

    static propTypes = {
    children: oneOfType([func, element]).isRequired,
    onHoverIn: func,
    onHoverOut: func
    };

    state = { isHovered: false };

    _handleMouseEnter = e => {
    if (hover.isEnabled && !this.state.isHovered) {
    const { onHoverIn } = this.props;
    if (onHoverIn) {
    onHoverIn();
    }
    this.setState(() => ({ isHovered: true }));
    }
    };

    _handleMouseLeave = e => {
    if (this.state.isHovered) {
    const { onHoverOut } = this.props;
    if (onHoverOut) {
    onHoverOut();
    }
    this.setState(() => ({ isHovered: false }));
    }
    };

    render() {
    const {
    children,
    /* eslint-disable */
    onHoverIn,
    onHoverOut
    /* eslint-enable */
    } = this.props;

    const child = typeof children === 'function' ? children(this.state.isHovered) : children;

    return React.cloneElement(React.Children.only(child), {
    onMouseEnter: this._handleMouseEnter,
    onMouseLeave: this._handleMouseLeave
    });
    }
    }

    export default Hoverable;
    38 changes: 38 additions & 0 deletions createHoverMonitor.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,38 @@
    import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';

    /**
    * Touch devices emulate mouse events. This functions makes it possible to know
    * if the current modality supports hover (including for multi-modality
    * devices).
    */
    const createHoverMonitor = () => {
    let isHoverEnabled = false;
    let lastTouchTime = 0;

    function enableHover() {
    if (isHoverEnabled || Date.now() - lastTouchTime < 500) {
    return;
    }
    isHoverEnabled = true;
    }

    function disableHover() {
    lastTouchTime = new Date();
    if (isHoverEnabled) {
    isHoverEnabled = false;
    }
    }

    if (canUseDOM) {
    document.addEventListener('touchstart', disableHover, true);
    document.addEventListener('mousemove', enableHover, true);
    }

    return {
    get isEnabled() {
    return isHoverEnabled;
    }
    };
    };

    export default createHoverMonitor;