Skip to content

Instantly share code, notes, and snippets.

@rdela
Forked from necolas/Hoverable.js
Created March 5, 2018 20:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rdela/60fb8a676d5b78cfede396297d4f8f15 to your computer and use it in GitHub Desktop.
Save rdela/60fb8a676d5b78cfede396297d4f8f15 to your computer and use it in GitHub Desktop.
Hover styles in React Native for Web
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;
import createHoverMonitor from './createHoverMonitor';
import { element, func, oneOfType } from 'prop-types';
import React, { Component } from 'react';
const hover = createHoverMonitor();
/**
* Use:
* <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';
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;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment