UNPKG

@es-react/react

Version:

Hippy react framework

229 lines (213 loc) 7.58 kB
/* * Tencent is pleased to support the open source community by making * Hippy available. * * Copyright (C) 2017-2019 THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { Fiber } from '@hippy/react-reconciler'; import { getFiberNodeFromId, getElementFromFiber, isNativeGesture, DOMEventPhase, } from '../utils/node'; import { trace, warn, isGlobalBubble, isCaptureEvent } from '../utils'; import HippyEventHub from './hub'; import Event from './event'; import {HippyTypes} from '../types' type EventParam = string[] | number[]; interface NativeEvent { id: number; currentId: number; nativeName: string; originalName: string; eventPhase: HippyTypes.EventPhase, params?: any } const eventHubs = new Map(); const componentName = ['%c[event]%c', 'color: green', 'color: auto']; function isNodePropFunction(prop: string, nextNodeItem: Fiber) { return !!(nextNodeItem.memoizedProps && typeof nextNodeItem.memoizedProps[prop] === 'function'); } /** * dispatchGestureEvent - dispatch event * @param {string} eventName * @param {NativeEvent} nativeEvent * @param {Fiber} currentItem * @param {Fiber} targetItem * @param {any} params * @param {HippyTypes.DOMEvent} domEvent */ function dispatchGestureEvent( eventName: string, nativeEvent: NativeEvent, currentItem: Fiber, targetItem: Fiber, params: any, domEvent: HippyTypes.DOMEvent, ) { try { let isStopBubble: any = false; const targetNode = getElementFromFiber(targetItem); const currentTargetNode = getElementFromFiber(currentItem); const { eventPhase } = domEvent; // handle target & capture phase event if (isNodePropFunction(eventName, currentItem) && isCaptureEvent(eventName) && [DOMEventPhase.AT_TARGET, DOMEventPhase.CAPTURING_PHASE].indexOf(eventPhase) > -1) { const syntheticEvent = new Event(eventName, currentTargetNode, targetNode); Object.assign(syntheticEvent, { eventPhase }, params); currentItem.memoizedProps[eventName](syntheticEvent); if (!syntheticEvent.bubbles && domEvent) { domEvent.stopPropagation(); } } if (isNodePropFunction(eventName, currentItem) && !isCaptureEvent(eventName) && [DOMEventPhase.AT_TARGET, DOMEventPhase.BUBBLING_PHASE].indexOf(eventPhase) > -1) { // handle target & bubbling phase event const syntheticEvent = new Event(eventName, currentTargetNode, targetNode); Object.assign(syntheticEvent, { eventPhase }, params); isStopBubble = currentItem.memoizedProps[eventName](syntheticEvent); // If callback have no return, use global bubble config to set isStopBubble. if (typeof isStopBubble !== 'boolean') { isStopBubble = !isGlobalBubble(); } // event bubbles flag has higher priority if (!syntheticEvent.bubbles) { isStopBubble = true; } if (isStopBubble && domEvent) { domEvent.stopPropagation(); } } } catch (err) { console.error(err); } } /** * dispatchUIEvent - dispatch ui event * @param {string} eventName * @param {NativeEvent} nativeEvent * @param {Fiber} currentItem * @param {Fiber} targetItem * @param {any} params * @param {HippyTypes.DOMEvent} domEvent */ function dispatchUIEvent( eventName: string, nativeEvent: NativeEvent, currentItem: Fiber, targetItem: Fiber, params: any, domEvent: HippyTypes.DOMEvent, ) { let isStopBubble: any = false; const targetNode = getElementFromFiber(targetItem); const currentTargetNode = getElementFromFiber(currentItem); try { const { eventPhase } = domEvent; // handle target & bubbling phase event if (isNodePropFunction(eventName, currentItem) && !isCaptureEvent(eventName) && [DOMEventPhase.AT_TARGET, DOMEventPhase.BUBBLING_PHASE].indexOf(eventPhase) > -1) { const syntheticEvent = new Event(eventName, currentTargetNode, targetNode); Object.assign(syntheticEvent, { eventPhase }, params); currentItem.memoizedProps[eventName](syntheticEvent); isStopBubble = !isGlobalBubble(); // event bubbles flag has higher priority if (!syntheticEvent.bubbles) { isStopBubble = true; } if (isStopBubble && domEvent) { domEvent.stopPropagation(); } } } catch (err) { console.error(err); } } function receiveComponentEvent(nativeEvent: NativeEvent, domEvent: HippyTypes.DOMEvent) { trace(...componentName, 'receiveComponentEvent', nativeEvent); if (!nativeEvent || !domEvent) { warn(...componentName, 'receiveComponentEvent', 'nativeEvent or domEvent not exist'); return; } const { id, currentId, nativeName, originalName, params = {} } = nativeEvent; const currentTargetNode = getFiberNodeFromId(currentId); const targetNode = getFiberNodeFromId(id); if (!currentTargetNode || !targetNode) { warn(...componentName, 'receiveComponentEvent', 'currentTargetNode or targetNode not exist'); return; } if (isNativeGesture(nativeName)) { dispatchGestureEvent(originalName, nativeEvent, currentTargetNode, targetNode, params, domEvent); } else { dispatchUIEvent(originalName, nativeEvent, currentTargetNode, targetNode, params, domEvent); } } function getHippyEventHub(eventName: any) { if (typeof eventName !== 'string') { throw new TypeError(`Invalid eventName for getHippyEventHub: ${eventName}`); } return eventHubs.get(eventName) || null; } function registerNativeEventHub(eventName: any) { trace(...componentName, 'registerNativeEventHub', eventName); if (typeof eventName !== 'string') { throw new TypeError(`Invalid eventName for registerNativeEventHub: ${eventName}`); } let targetEventHub = eventHubs.get(eventName); if (!targetEventHub) { targetEventHub = new HippyEventHub(eventName); eventHubs.set(eventName, targetEventHub); } return targetEventHub; } function unregisterNativeEventHub(eventName: any) { if (typeof eventName !== 'string') { throw new TypeError(`Invalid eventName for unregisterNativeEventHub: ${eventName}`); } if (eventHubs.has(eventName)) { eventHubs.delete(eventName); } } function receiveNativeEvent(nativeEvent: EventParam) { trace(...componentName, 'receiveNativeEvent', nativeEvent); if (!nativeEvent || !Array.isArray(nativeEvent) || nativeEvent.length < 2) { throw new TypeError(`Invalid params for receiveNativeEvent: ${JSON.stringify(nativeEvent)}`); } const [eventName, eventParams] = nativeEvent; if (typeof eventName !== 'string') { throw new TypeError('Invalid arguments for nativeEvent eventName'); } const currEventHub = getHippyEventHub(eventName); if (!currEventHub) { return; } currEventHub.notifyEvent(eventParams); } const EventDispatcher = { registerNativeEventHub, getHippyEventHub, unregisterNativeEventHub, receiveNativeEvent, receiveComponentEvent, }; if (global.__GLOBAL__) { global.__GLOBAL__.jsModuleList.EventDispatcher = EventDispatcher; } export default EventDispatcher;