')
);
+ if (
+ process.env.NODE_ENV !== 'production' &&
+ Touchable.TOUCH_TARGET_DEBUG &&
+ child.type &&
+ child.type.displayName === 'View'
+ ) {
+ children = React.Children.toArray(children);
+ children.push(Touchable.renderDebugView({ color: 'red', hitSlop: this.props.hitSlop }));
+ }
const style = Touchable.TOUCH_TARGET_DEBUG && child.type && child.type.displayName === 'Text'
? [styles.root, this.props.disabled && styles.disabled, child.props.style, { color: 'red' }]
: [styles.root, this.props.disabled && styles.disabled, child.props.style];
diff --git a/src/components/View/__tests__/__snapshots__/index-test.js.snap b/src/components/View/__tests__/__snapshots__/index-test.js.snap
index b321c25c..9dd2ab44 100644
--- a/src/components/View/__tests__/__snapshots__/index-test.js.snap
+++ b/src/components/View/__tests__/__snapshots__/index-test.js.snap
@@ -11,6 +11,39 @@ exports[`components/View prop "children" 1`] = `
`;
+exports[`components/View prop "hitSlop" handles partial offsets 1`] = `
+
+
+
+`;
+
+exports[`components/View prop "hitSlop" renders a span with negative position offsets 1`] = `
+
+
+
+`;
+
exports[`components/View prop "pointerEvents" 1`] = `
{
expect(component.toJSON()).toMatchSnapshot();
});
+ describe('prop "hitSlop"', () => {
+ it('renders a span with negative position offsets', () => {
+ const component = renderer.create(
+
+ );
+ expect(component.toJSON()).toMatchSnapshot();
+ });
+
+ it('handles partial offsets', () => {
+ const component = renderer.create();
+ expect(component.toJSON()).toMatchSnapshot();
+ });
+ });
+
test('prop "pointerEvents"', () => {
const component = renderer.create();
expect(component.toJSON()).toMatchSnapshot();
diff --git a/src/components/View/index.js b/src/components/View/index.js
index 3ebc0611..d8f6e3ba 100644
--- a/src/components/View/index.js
+++ b/src/components/View/index.js
@@ -4,10 +4,21 @@ import createDOMElement from '../../modules/createDOMElement';
import getAccessibilityRole from '../../modules/getAccessibilityRole';
import StyleSheet from '../../apis/StyleSheet';
import ViewPropTypes from './ViewPropTypes';
-import { Component, PropTypes } from 'react';
+import React, { Component, PropTypes } from 'react';
const emptyObject = {};
+const calculateHitSlopStyle = hitSlop => {
+ const hitStyle = {};
+ for (const prop in hitSlop) {
+ if (hitSlop.hasOwnProperty(prop)) {
+ const value = hitSlop[prop];
+ hitStyle[prop] = value > 0 ? (-1) * value : 0;
+ }
+ }
+ return hitStyle;
+};
+
class View extends Component {
static displayName = 'View';
@@ -33,10 +44,10 @@ class View extends Component {
render() {
const {
+ hitSlop,
style,
/* eslint-disable */
collapsable,
- hitSlop,
onAccessibilityTap,
onLayout,
onMagicTap,
@@ -50,6 +61,14 @@ class View extends Component {
otherProps.style = [styles.initial, isButton && styles.buttonOnly, style];
+ if (hitSlop) {
+ const hitSlopStyle = calculateHitSlopStyle(hitSlop);
+ const hitSlopChild = createDOMElement('span', { style: [styles.hitSlop, hitSlopStyle] });
+ otherProps.children = React.Children.toArray(otherProps.children);
+ otherProps.children.unshift(hitSlopChild);
+ otherProps.style.unshift(styles.hasHitSlop);
+ }
+
const component = isInAButtonView ? 'span' : 'div';
return createDOMElement(component, otherProps);
}
@@ -82,6 +101,15 @@ const styles = StyleSheet.create({
},
buttonOnly: {
appearance: 'none'
+ },
+ // this zIndex ordering positions the hitSlop above the View but behind
+ // its children
+ hasHitSlop: {
+ zIndex: 0
+ },
+ hitSlop: {
+ ...StyleSheet.absoluteFillObject,
+ zIndex: -1
}
});