It seems to me that _React Native Web_ should have an onHover prop just as <View> and <Text> support onPress. Perhaps I'm missing something.
The thing is you need 2 callbacks to know on and off. But yeah, onMouseEnter & onMouseLeave are related to mouse...
excellent thanks @MoOx that solves my problem--didn't know those callbacks were available. it's not available on Touchable components if anyone's wondering, but on <Text> and probably I assume <View as well.
It's starting to seem like a library of web-specific react components should emerge, similar to how the tvOS efforts require components for their unique way of "focusing" elements. For example, <TouchableOpacityHover> would have 2 different opacity based on if it's pressed or simply hovered.
I created a utility component to make it easy to add a hover style:
import React, { Component } from 'react'
import { TouchableOpacity } from 'react-native'
export default class HoverableOpacity extends Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
const { outerStyle, hoverStyle } = this.props
return (
<TouchableOpacity
activeOpacity={1}
style={[{ cursor: 'inherit' }, outerStyle, this.state.hover ? hoverStyle : {}]}
onMouseEnter={() => this.setState({ hover: true })}
onMouseLeave={() => this.setState({ hover: false })}
>
<TouchableOpacity {...this.props} />
</TouchableOpacity>
)
}
}
HoverableOpacity.propTypes = {
hoverStyle: React.PropTypes.shape({}),
outerStyle: React.PropTypes.shape({}),
}
Use HoverableOpacity in place of TouchableOpacity.
It can take two new props:
Style to apply while component is hovered.
hoverStyle={{ backgroundColor: 'hsla(0,0%,100%,0.1)' }}
Style applied to the Hoverable container.
Useful for adding margins outside the hover.
outerStyle={{ margin: 30 }}
You should use setNativeProps (like the touchables do) to update the style without triggering a render of the sub tree.
I wrote a component that uses setNativeProps to set styles on hover in case anyone wants to see what that looks like:
import React from 'react'
import { View } from 'react-native'
class HoverableView extends React.Component {
setStyles = (styles) => {
this.root.setNativeProps({
style: styles,
})
}
render() {
const { onHover, style, ...passThrough } = this.props
return (
<View
ref={(component) => { this.root = component }}
onMouseEnter={() => this.setStyles(onHover)}
onMouseLeave={() => this.setStyles(style)}
style={style}
{...passThrough}
/>
)
}
}
export default HoverableView
Called like this:
<HoverableView
style={{ backgroundColor: 'transparent', flex: 1 }}
onHover={{ backgroundColor: '#ff0000' }}
>
<Text>Foo</Text>
</HoverableView>
One thing to be aware of is that if a style attribute is passed through onHover but is not in the style prop, it will not be overwritten onMouseLeave. (That's why backgroundColor: 'transparent' is set in the style prop of the example)
I created an example that also implements pseudo classes other than hover.
As an example, please try it.
https://github.com/Shagamii/pseudo-class-example/blob/master/src/AccessibleComponent.js
Most helpful comment
I wrote a component that uses setNativeProps to set styles on hover in case anyone wants to see what that looks like:
Called like this:
One thing to be aware of is that if a style attribute is passed through onHover but is not in the style prop, it will not be overwritten onMouseLeave. (That's why
backgroundColor: 'transparent'is set in the style prop of the example)