react-native-dom-expo
Version:
A patch library to make Expo work with react-native-dom
204 lines (168 loc) • 4.85 kB
JavaScript
import React from 'react';
import { TouchableWithoutFeedback } from 'react-native';
import State from './State';
function handleHandlerStateChange(props, event, oldState, state) {
const { enabled, onHandlerStateChange } = props;
if (enabled !== false && onHandlerStateChange) {
const {
nativeEvent: {
locationX: x,
locationY: y,
pageX: absoluteX,
pageY: absoluteY,
},
} = event;
onHandlerStateChange({
nativeEvent: {
oldState,
state,
x,
y,
absoluteX,
absoluteY,
pointerInside: true,
},
});
}
}
function handleFailed(props, event) {
handleHandlerStateChange(props, event, State.ACTIVE, State.FAILED);
}
function handleEnd(props, event) {
handleHandlerStateChange(props, event, State.ACTIVE, State.END);
}
function handleActivate(props, event) {
handleHandlerStateChange(props, event, State.BEGAN, State.ACTIVE);
}
function handleBegan(props, event) {
handleHandlerStateChange(props, event, State.UNDETERMINED, State.BEGAN);
}
class UnimplementedGestureHandler extends React.Component {
setNativeProps = () => {
// Do nothing
};
render() {
return this.props.children;
}
}
const handlers = {
NativeViewGestureHandler: class NativeViewGestureHandler extends React.Component {
render() {
const { children } = this.props;
return children;
}
},
TapGestureHandler: class TapGestureHandler extends React.Component {
static defaultProps = {
numberOfTaps: 1,
maxDurationMs: 500,
maxDelayMs: 500,
minPointers: 1,
maxDeltaX: Number.MAX_SAFE_INTEGER,
maxDeltaY: Number.MAX_SAFE_INTEGER,
maxDist: Number.MAX_SAFE_INTEGER,
};
hasBegun = false;
touchBank = [];
timeout = null;
setNativeProps() {}
clearState = () => {
this.hasBegun = false;
this.touchBank = [];
window.clearTimeout(this.timeout);
};
handlePressIn = event => {
const { maxDelayMs } = this.props;
if (!this.hasBegun) {
event.persist();
this.hasBegun = true;
handleBegan(this.props, event);
// Cancel if not finished in time
this.timeout = window.setTimeout(() => {
if (this.hasBegun) {
this.clearState();
handleFailed(this.props, event);
}
}, maxDelayMs);
}
};
handlePressOut = event => {
const {
touchHistory: { touchBank = [] },
} = event;
const { maxDeltaX, maxDeltaY, maxDurationMs, numberOfTaps } = this.props;
this.touchBank = this.touchBank.concat(touchBank);
// Check if all touches are valid
const areTouchesValid = this.touchBank.every(touch => {
const {
currentPageX,
currentPageY,
currentTimeStamp,
startPageX,
startPageY,
startTimeStamp,
} = touch;
// Check if touch took longer than it may
if (startTimeStamp + maxDurationMs < currentTimeStamp) {
return false;
}
// Check if touch moved too far away
if (
startPageX + maxDeltaX < currentPageX ||
startPageX - maxDeltaX > currentPageX
) {
return false;
}
// Check if touch moved too far away
if (
startPageY + maxDeltaY < currentPageY ||
startPageY - maxDeltaY > currentPageY
) {
return false;
}
return true;
});
// Check if all touches were valid and the necessary number of touches was achieved
if (!areTouchesValid) {
this.clearState();
handleFailed(this.props, event);
} else if (this.touchBank.length >= numberOfTaps) {
handleActivate(this.props, event);
this.clearState();
handleEnd(this.props, event);
}
};
render() {
const { children, style } = this.props;
return (
<TouchableWithoutFeedback
style={style}
onPressIn={this.handlePressIn}
onPressOut={this.handlePressOut}>
{children}
</TouchableWithoutFeedback>
);
}
},
};
export default function createHandler(handlerName, propTypes = {}) {
class Handler extends React.Component {
static displayName = handlerName;
static propTypes = propTypes;
_refHandler = node => {
this._viewNode = node;
};
setNativeProps = (...args) => {
this._viewNode.setNativeProps(...args);
};
render() {
let Handler = handlers[handlerName];
if (!Handler) {
console.warn(`${handlerName} is not yet supported on web.`);
Handler = UnimplementedGestureHandler;
}
return <Handler ref={this._refHandler} {...this.props} />;
}
}
return Handler;
}