"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = createHandler; var React = _interopRequireWildcard(require("react")); var _reactNative = require("react-native"); var _areEqual = _interopRequireDefault(require("fbjs/lib/areEqual")); var _RNGestureHandlerModule = _interopRequireDefault(require("../RNGestureHandlerModule")); var _State = require("../State"); var _UIManager$getViewMan, _UIManager$getViewMan2, _UIManager$getConstan; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function findNodeHandle(node) { if (_reactNative.Platform.OS === 'web') return node; return (0, _reactNative.findNodeHandle)(node); } const { UIManager = {} } = _reactNative.NativeModules; const customGHEventsConfig = { onGestureHandlerEvent: { registrationName: 'onGestureHandlerEvent' }, onGestureHandlerStateChange: { registrationName: 'onGestureHandlerStateChange' } }; // Add gesture specific events to genericDirectEventTypes object exported from UIManager // native module. // Once new event types are registered with react it is possible to dispatch these // events to all kind of native views. UIManager.genericDirectEventTypes = { ...UIManager.genericDirectEventTypes, ...customGHEventsConfig }; // In newer versions of RN the `genericDirectEventTypes` is located in the object // returned by UIManager.getViewManagerConfig('getConstants') or in older RN UIManager.getConstants(), we need to add it there as well to make // it compatible with RN 61+ const UIManagerConstants = (_UIManager$getViewMan = (_UIManager$getViewMan2 = UIManager.getViewManagerConfig) === null || _UIManager$getViewMan2 === void 0 ? void 0 : _UIManager$getViewMan2.call(UIManager, 'getConstants')) !== null && _UIManager$getViewMan !== void 0 ? _UIManager$getViewMan : (_UIManager$getConstan = UIManager.getConstants) === null || _UIManager$getConstan === void 0 ? void 0 : _UIManager$getConstan.call(UIManager); if (UIManagerConstants) { UIManagerConstants.genericDirectEventTypes = { ...UIManagerConstants.genericDirectEventTypes, ...customGHEventsConfig }; } // Wrap JS responder calls and notify gesture handler manager const { setJSResponder: oldSetJSResponder = () => {//no operation }, clearJSResponder: oldClearJSResponder = () => {//no operation } } = UIManager; UIManager.setJSResponder = (tag, blockNativeResponder) => { _RNGestureHandlerModule.default.handleSetJSResponder(tag, blockNativeResponder); oldSetJSResponder(tag, blockNativeResponder); }; UIManager.clearJSResponder = () => { _RNGestureHandlerModule.default.handleClearJSResponder(); oldClearJSResponder(); }; let handlerTag = 1; const handlerIDToTag = {}; function isConfigParam(param, name) { // param !== Object(param) returns false if `param` is a function // or an object and returns true if `param` is null return param !== undefined && (param !== Object(param) || !('__isNative' in param)) && name !== 'onHandlerStateChange' && name !== 'onGestureEvent'; } function filterConfig(props, validProps, defaults = {}) { const res = { ...defaults }; validProps.forEach(key => { const value = props[key]; if (isConfigParam(value, key)) { let value = props[key]; if (key === 'simultaneousHandlers' || key === 'waitFor') { value = transformIntoHandlerTags(props[key]); } else if (key === 'hitSlop') { if (typeof value !== 'object') { value = { top: value, left: value, bottom: value, right: value }; } } res[key] = value; } }); return res; } function transformIntoHandlerTags(handlerIDs) { if (!Array.isArray(handlerIDs)) { handlerIDs = [handlerIDs]; } if (_reactNative.Platform.OS === 'web') { return handlerIDs.map(({ current }) => current).filter(handle => handle); } // converts handler string IDs into their numeric tags return handlerIDs.map(handlerID => { var _handlerID$current; return handlerIDToTag[handlerID] || ((_handlerID$current = handlerID.current) === null || _handlerID$current === void 0 ? void 0 : _handlerID$current.handlerTag) || -1; }).filter(handlerTag => handlerTag > 0); } function hasUnresolvedRefs(props) { // TODO(TS) - add type for extract arg const extract = refs => { if (!Array.isArray(refs)) { return refs && refs.current === null; } return refs.some(r => r && r.current === null); }; return extract(props['simultaneousHandlers']) || extract(props['waitFor']); } const stateToPropMappings = { [_State.State.UNDETERMINED]: undefined, [_State.State.BEGAN]: 'onBegan', [_State.State.FAILED]: 'onFailed', [_State.State.CANCELLED]: 'onCancelled', [_State.State.ACTIVE]: 'onActivated', [_State.State.END]: 'onEnded' }; // TODO(TS) - make sure that BaseGestureHandlerProps doesn't need other generic parameter to work with custom properties. function createHandler({ name, allowedProps = [], config = {}, transformProps, customNativeProps = [] }) { class Handler extends React.Component { constructor(props) { super(props); _defineProperty(this, "handlerTag", void 0); _defineProperty(this, "config", void 0); _defineProperty(this, "propsRef", void 0); _defineProperty(this, "viewNode", void 0); _defineProperty(this, "viewTag", void 0); _defineProperty(this, "updateEnqueued", null); _defineProperty(this, "onGestureHandlerEvent", event => { if (event.nativeEvent.handlerTag === this.handlerTag) { var _this$props$onGesture, _this$props; (_this$props$onGesture = (_this$props = this.props).onGestureEvent) === null || _this$props$onGesture === void 0 ? void 0 : _this$props$onGesture.call(_this$props, event); } else { var _this$props$onGesture2, _this$props2; (_this$props$onGesture2 = (_this$props2 = this.props).onGestureHandlerEvent) === null || _this$props$onGesture2 === void 0 ? void 0 : _this$props$onGesture2.call(_this$props2, event); } }); _defineProperty(this, "onGestureHandlerStateChange", event => { if (event.nativeEvent.handlerTag === this.handlerTag) { var _this$props$onHandler, _this$props3; (_this$props$onHandler = (_this$props3 = this.props).onHandlerStateChange) === null || _this$props$onHandler === void 0 ? void 0 : _this$props$onHandler.call(_this$props3, event); const state = event.nativeEvent.state; const stateEventName = stateToPropMappings[state]; const eventHandler = stateEventName && this.props[stateEventName]; if (eventHandler && typeof eventHandler === 'function') { eventHandler(event); } } else { var _this$props$onGesture3, _this$props4; (_this$props$onGesture3 = (_this$props4 = this.props).onGestureHandlerStateChange) === null || _this$props$onGesture3 === void 0 ? void 0 : _this$props$onGesture3.call(_this$props4, event); } }); _defineProperty(this, "refHandler", node => { this.viewNode = node; const child = React.Children.only(this.props.children); // TODO(TS) fix ref type const { ref } = child; if (ref !== null) { if (typeof ref === 'function') { ref(node); } else { ref.current = node; } } }); _defineProperty(this, "createGestureHandler", newConfig => { this.config = newConfig; _RNGestureHandlerModule.default.createGestureHandler(name, this.handlerTag, newConfig); }); _defineProperty(this, "attachGestureHandler", newViewTag => { this.viewTag = newViewTag; if (_reactNative.Platform.OS === 'web') { // typecast due to dynamic resolution, attachGestureHandler should have web version signature in this branch _RNGestureHandlerModule.default.attachGestureHandler(this.handlerTag, newViewTag, this.propsRef); } else { _RNGestureHandlerModule.default.attachGestureHandler(this.handlerTag, newViewTag); } }); _defineProperty(this, "updateGestureHandler", newConfig => { this.config = newConfig; _RNGestureHandlerModule.default.updateGestureHandler(this.handlerTag, newConfig); }); this.handlerTag = handlerTag++; this.config = {}; this.propsRef = /*#__PURE__*/React.createRef(); if (props.id) { if (handlerIDToTag[props.id] !== undefined) { throw new Error("Handler with ID \"".concat(props.id, "\" already registered")); } handlerIDToTag[props.id] = this.handlerTag; } } componentDidMount() { const props = this.props; if (hasUnresolvedRefs(props)) { // If there are unresolved refs (e.g. ".current" has not yet been set) // passed as `simultaneousHandlers` or `waitFor`, we enqueue a call to // _update method that will try to update native handler props using // setImmediate. This makes it so _update function gets called after all // react components are mounted and we expect the missing ref object to // be resolved by then. this.updateEnqueued = setImmediate(() => { this.updateEnqueued = null; this.update(); }); } this.createGestureHandler(filterConfig(transformProps ? transformProps(this.props) : this.props, [...allowedProps, ...customNativeProps], config)); this.attachGestureHandler(findNodeHandle(this.viewNode)); // TODO(TS) - check if this can be null } componentDidUpdate() { const viewTag = findNodeHandle(this.viewNode); if (this.viewTag !== viewTag) { this.attachGestureHandler(viewTag); // TODO(TS) - check interaction between _viewTag & findNodeHandle } this.update(); } componentWillUnmount() { _RNGestureHandlerModule.default.dropGestureHandler(this.handlerTag); if (this.updateEnqueued) { clearImmediate(this.updateEnqueued); } // We can't use this.props.id directly due to TS generic type narrowing bug, see https://github.com/microsoft/TypeScript/issues/13995 for more context const handlerID = this.props.id; if (handlerID) { // eslint-disable-next-line @typescript-eslint/no-dynamic-delete delete handlerIDToTag[handlerID]; } } update() { const newConfig = filterConfig(transformProps ? transformProps(this.props) : this.props, [...allowedProps, ...customNativeProps], config); if (!(0, _areEqual.default)(this.config, newConfig)) { this.updateGestureHandler(newConfig); } } setNativeProps(updates) { const mergedProps = { ...this.props, ...updates }; const newConfig = filterConfig(transformProps ? transformProps(mergedProps) : mergedProps, [...allowedProps, ...customNativeProps], config); this.updateGestureHandler(newConfig); } render() { let gestureEventHandler = this.onGestureHandlerEvent; // Another instance of https://github.com/microsoft/TypeScript/issues/13995 const { onGestureEvent, onGestureHandlerEvent } = this.props; if (onGestureEvent && typeof onGestureEvent !== 'function') { // If it's not a method it should be an native Animated.event // object. We set it directly as the handler for the view // In this case nested handlers are not going to be supported if (onGestureHandlerEvent) { throw new Error('Nesting touch handlers with native animated driver is not supported yet'); } gestureEventHandler = onGestureEvent; } else { if (onGestureHandlerEvent && typeof onGestureHandlerEvent !== 'function') { throw new Error('Nesting touch handlers with native animated driver is not supported yet'); } } let gestureStateEventHandler = this.onGestureHandlerStateChange; // Another instance of https://github.com/microsoft/TypeScript/issues/13995 const { onHandlerStateChange, onGestureHandlerStateChange } = this.props; if (onHandlerStateChange && typeof onHandlerStateChange !== 'function') { // If it's not a method it should be an native Animated.event // object. We set it directly as the handler for the view // In this case nested handlers are not going to be supported if (onGestureHandlerStateChange) { throw new Error('Nesting touch handlers with native animated driver is not supported yet'); } gestureStateEventHandler = onHandlerStateChange; } else { if (onGestureHandlerStateChange && typeof onGestureHandlerStateChange !== 'function') { throw new Error('Nesting touch handlers with native animated driver is not supported yet'); } } const events = { onGestureHandlerEvent: gestureEventHandler, onGestureHandlerStateChange: gestureStateEventHandler }; this.propsRef.current = events; const child = React.Children.only(this.props.children); let grandChildren = child.props.children; if (_reactNative.Touchable.TOUCH_TARGET_DEBUG && child.type && (child.type === 'RNGestureHandlerButton' || child.type.name === 'View' || child.type.displayName === 'View')) { grandChildren = React.Children.toArray(grandChildren); grandChildren.push(_reactNative.Touchable.renderDebugView({ color: 'mediumspringgreen', hitSlop: child.props.hitSlop })); } return /*#__PURE__*/React.cloneElement(child, { ref: this.refHandler, collapsable: false, ...events }, grandChildren); } } _defineProperty(Handler, "displayName", name); return Handler; } //# sourceMappingURL=createHandler.js.map