/** @license React v16.0.0 * react-dom-unstable-native-dependencies.development.js * * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ 'use strict'; if (process.env.NODE_ENV !== "production") { (function() { 'use strict'; var invariant = require('fbjs/lib/invariant'); var require$$0 = require('fbjs/lib/warning'); var objectAssign$1 = require('object-assign'); var emptyFunction = require('fbjs/lib/emptyFunction'); var reactDom = require('react-dom'); /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @providesModule reactProdInvariant * */ var ReactErrorUtils = { // Used by Fiber to simulate a try-catch. _caughtError: null, _hasCaughtError: false, // Used by event system to capture/rethrow the first error. _rethrowError: null, _hasRethrowError: false, injection: { injectErrorUtils: function (injectedErrorUtils) { !(typeof injectedErrorUtils.invokeGuardedCallback === 'function') ? invariant(false, 'Injected invokeGuardedCallback() must be a function.') : void 0; invokeGuardedCallback = injectedErrorUtils.invokeGuardedCallback; } }, /** * Call a function while guarding against errors that happens within it. * Returns an error if it throws, otherwise null. * * In production, this is implemented using a try-catch. The reason we don't * use a try-catch directly is so that we can swap out a different * implementation in DEV mode. * * @param {String} name of the guard to use for logging or debugging * @param {Function} func The function to invoke * @param {*} context The context to use when calling the function * @param {...*} args Arguments for function */ invokeGuardedCallback: function (name, func, context, a, b, c, d, e, f) { invokeGuardedCallback.apply(ReactErrorUtils, arguments); }, /** * Same as invokeGuardedCallback, but instead of returning an error, it stores * it in a global so it can be rethrown by `rethrowCaughtError` later. * TODO: See if _caughtError and _rethrowError can be unified. * * @param {String} name of the guard to use for logging or debugging * @param {Function} func The function to invoke * @param {*} context The context to use when calling the function * @param {...*} args Arguments for function */ invokeGuardedCallbackAndCatchFirstError: function (name, func, context, a, b, c, d, e, f) { ReactErrorUtils.invokeGuardedCallback.apply(this, arguments); if (ReactErrorUtils.hasCaughtError()) { var error = ReactErrorUtils.clearCaughtError(); if (!ReactErrorUtils._hasRethrowError) { ReactErrorUtils._hasRethrowError = true; ReactErrorUtils._rethrowError = error; } } }, /** * During execution of guarded functions we will capture the first error which * we will rethrow to be handled by the top level error handler. */ rethrowCaughtError: function () { return rethrowCaughtError.apply(ReactErrorUtils, arguments); }, hasCaughtError: function () { return ReactErrorUtils._hasCaughtError; }, clearCaughtError: function () { if (ReactErrorUtils._hasCaughtError) { var error = ReactErrorUtils._caughtError; ReactErrorUtils._caughtError = null; ReactErrorUtils._hasCaughtError = false; return error; } else { invariant(false, 'clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue.'); } } }; var invokeGuardedCallback = function (name, func, context, a, b, c, d, e, f) { ReactErrorUtils._hasCaughtError = false; ReactErrorUtils._caughtError = null; var funcArgs = Array.prototype.slice.call(arguments, 3); try { func.apply(context, funcArgs); } catch (error) { ReactErrorUtils._caughtError = error; ReactErrorUtils._hasCaughtError = true; } }; { // In DEV mode, we swap out invokeGuardedCallback for a special version // that plays more nicely with the browser's DevTools. The idea is to preserve // "Pause on exceptions" behavior. Because React wraps all user-provided // functions in invokeGuardedCallback, and the production version of // invokeGuardedCallback uses a try-catch, all user exceptions are treated // like caught exceptions, and the DevTools won't pause unless the developer // takes the extra step of enabling pause on caught exceptions. This is // untintuitive, though, because even though React has caught the error, from // the developer's perspective, the error is uncaught. // // To preserve the expected "Pause on exceptions" behavior, we don't use a // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake // DOM node, and call the user-provided callback from inside an event handler // for that fake event. If the callback throws, the error is "captured" using // a global event handler. But because the error happens in a different // event loop context, it does not interrupt the normal program flow. // Effectively, this gives us try-catch behavior without actually using // try-catch. Neat! // Check that the browser supports the APIs we need to implement our special // DEV version of invokeGuardedCallback if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function' && typeof document !== 'undefined' && typeof document.createEvent === 'function') { var fakeNode = document.createElement('react'); var invokeGuardedCallbackDev = function (name, func, context, a, b, c, d, e, f) { // Keeps track of whether the user-provided callback threw an error. We // set this to true at the beginning, then set it to false right after // calling the function. If the function errors, `didError` will never be // set to false. This strategy works even if the browser is flaky and // fails to call our global error handler, because it doesn't rely on // the error event at all. var didError = true; // Create an event handler for our fake event. We will synchronously // dispatch our fake event using `dispatchEvent`. Inside the handler, we // call the user-provided callback. var funcArgs = Array.prototype.slice.call(arguments, 3); function callCallback() { // We immediately remove the callback from event listeners so that // nested `invokeGuardedCallback` calls do not clash. Otherwise, a // nested call would trigger the fake event handlers of any call higher // in the stack. fakeNode.removeEventListener(evtType, callCallback, false); func.apply(context, funcArgs); didError = false; } // Create a global error event handler. We use this to capture the value // that was thrown. It's possible that this error handler will fire more // than once; for example, if non-React code also calls `dispatchEvent` // and a handler for that event throws. We should be resilient to most of // those cases. Even if our error event handler fires more than once, the // last error event is always used. If the callback actually does error, // we know that the last error event is the correct one, because it's not // possible for anything else to have happened in between our callback // erroring and the code that follows the `dispatchEvent` call below. If // the callback doesn't error, but the error event was fired, we know to // ignore it because `didError` will be false, as described above. var error = void 0; // Use this to track whether the error event is ever called. var didSetError = false; var isCrossOriginError = false; function onError(event) { error = event.error; didSetError = true; if (error === null && event.colno === 0 && event.lineno === 0) { isCrossOriginError = true; } } // Create a fake event type. var evtType = 'react-' + (name ? name : 'invokeguardedcallback'); // Attach our event handlers window.addEventListener('error', onError); fakeNode.addEventListener(evtType, callCallback, false); // Synchronously dispatch our fake event. If the user-provided function // errors, it will trigger our global error handler. var evt = document.createEvent('Event'); evt.initEvent(evtType, false, false); fakeNode.dispatchEvent(evt); if (didError) { if (!didSetError) { // The callback errored, but the error event never fired. error = new Error('An error was thrown inside one of your components, but React ' + "doesn't know what it was. This is likely due to browser " + 'flakiness. React does its best to preserve the "Pause on ' + 'exceptions" behavior of the DevTools, which requires some ' + "DEV-mode only tricks. It's possible that these don't work in " + 'your browser. Try triggering the error in production mode, ' + 'or switching to a modern browser. If you suspect that this is ' + 'actually an issue with React, please file an issue.'); } else if (isCrossOriginError) { error = new Error("A cross-origin error was thrown. React doesn't have access to " + 'the actual error object in development. ' + 'See https://fb.me/react-crossorigin-error for more information.'); } ReactErrorUtils._hasCaughtError = true; ReactErrorUtils._caughtError = error; } else { ReactErrorUtils._hasCaughtError = false; ReactErrorUtils._caughtError = null; } // Remove our event listeners window.removeEventListener('error', onError); }; invokeGuardedCallback = invokeGuardedCallbackDev; } } var rethrowCaughtError = function () { if (ReactErrorUtils._hasRethrowError) { var error = ReactErrorUtils._rethrowError; ReactErrorUtils._rethrowError = null; ReactErrorUtils._hasRethrowError = false; throw error; } }; var ReactErrorUtils_1 = ReactErrorUtils; { var warning = require$$0; } /** * Injected dependencies: */ /** * - `ComponentTree`: [required] Module that can convert between React instances * and actual node references. */ var ComponentTree; var injection = { injectComponentTree: function (Injected) { ComponentTree = Injected; { warning(Injected && Injected.getNodeFromInstance && Injected.getInstanceFromNode, 'EventPluginUtils.injection.injectComponentTree(...): Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.'); } } }; function isEndish(topLevelType) { return topLevelType === 'topMouseUp' || topLevelType === 'topTouchEnd' || topLevelType === 'topTouchCancel'; } function isMoveish(topLevelType) { return topLevelType === 'topMouseMove' || topLevelType === 'topTouchMove'; } function isStartish(topLevelType) { return topLevelType === 'topMouseDown' || topLevelType === 'topTouchStart'; } var validateEventDispatches; { validateEventDispatches = function (event) { var dispatchListeners = event._dispatchListeners; var dispatchInstances = event._dispatchInstances; var listenersIsArr = Array.isArray(dispatchListeners); var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0; var instancesIsArr = Array.isArray(dispatchInstances); var instancesLen = instancesIsArr ? dispatchInstances.length : dispatchInstances ? 1 : 0; warning(instancesIsArr === listenersIsArr && instancesLen === listenersLen, 'EventPluginUtils: Invalid `event`.'); }; } /** * Dispatch the event to the listener. * @param {SyntheticEvent} event SyntheticEvent to handle * @param {boolean} simulated If the event is simulated (changes exn behavior) * @param {function} listener Application-level callback * @param {*} inst Internal component instance */ function executeDispatch(event, simulated, listener, inst) { var type = event.type || 'unknown-event'; event.currentTarget = EventPluginUtils.getNodeFromInstance(inst); ReactErrorUtils_1.invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); event.currentTarget = null; } /** * Standard/simple iteration through an event's collected dispatches. */ function executeDispatchesInOrder(event, simulated) { var dispatchListeners = event._dispatchListeners; var dispatchInstances = event._dispatchInstances; { validateEventDispatches(event); } if (Array.isArray(dispatchListeners)) { for (var i = 0; i < dispatchListeners.length; i++) { if (event.isPropagationStopped()) { break; } // Listeners and Instances are two parallel arrays that are always in sync. executeDispatch(event, simulated, dispatchListeners[i], dispatchInstances[i]); } } else if (dispatchListeners) { executeDispatch(event, simulated, dispatchListeners, dispatchInstances); } event._dispatchListeners = null; event._dispatchInstances = null; } /** * Standard/simple iteration through an event's collected dispatches, but stops * at the first dispatch execution returning true, and returns that id. * * @return {?string} id of the first dispatch execution who's listener returns * true, or null if no listener returned true. */ function executeDispatchesInOrderStopAtTrueImpl(event) { var dispatchListeners = event._dispatchListeners; var dispatchInstances = event._dispatchInstances; { validateEventDispatches(event); } if (Array.isArray(dispatchListeners)) { for (var i = 0; i < dispatchListeners.length; i++) { if (event.isPropagationStopped()) { break; } // Listeners and Instances are two parallel arrays that are always in sync. if (dispatchListeners[i](event, dispatchInstances[i])) { return dispatchInstances[i]; } } } else if (dispatchListeners) { if (dispatchListeners(event, dispatchInstances)) { return dispatchInstances; } } return null; } /** * @see executeDispatchesInOrderStopAtTrueImpl */ function executeDispatchesInOrderStopAtTrue(event) { var ret = executeDispatchesInOrderStopAtTrueImpl(event); event._dispatchInstances = null; event._dispatchListeners = null; return ret; } /** * Execution of a "direct" dispatch - there must be at most one dispatch * accumulated on the event or it is considered an error. It doesn't really make * sense for an event with multiple dispatches (bubbled) to keep track of the * return values at each dispatch execution, but it does tend to make sense when * dealing with "direct" dispatches. * * @return {*} The return value of executing the single dispatch. */ function executeDirectDispatch(event) { { validateEventDispatches(event); } var dispatchListener = event._dispatchListeners; var dispatchInstance = event._dispatchInstances; !!Array.isArray(dispatchListener) ? invariant(false, 'executeDirectDispatch(...): Invalid `event`.') : void 0; event.currentTarget = dispatchListener ? EventPluginUtils.getNodeFromInstance(dispatchInstance) : null; var res = dispatchListener ? dispatchListener(event) : null; event.currentTarget = null; event._dispatchListeners = null; event._dispatchInstances = null; return res; } /** * @param {SyntheticEvent} event * @return {boolean} True iff number of dispatches accumulated is greater than 0. */ function hasDispatches(event) { return !!event._dispatchListeners; } /** * General utilities that are useful in creating custom Event Plugins. */ var EventPluginUtils = { isEndish: isEndish, isMoveish: isMoveish, isStartish: isStartish, executeDirectDispatch: executeDirectDispatch, executeDispatchesInOrder: executeDispatchesInOrder, executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue, hasDispatches: hasDispatches, getFiberCurrentPropsFromNode: function (node) { return ComponentTree.getFiberCurrentPropsFromNode(node); }, getInstanceFromNode: function (node) { return ComponentTree.getInstanceFromNode(node); }, getNodeFromInstance: function (node) { return ComponentTree.getNodeFromInstance(node); }, injection: injection }; var EventPluginUtils_1 = EventPluginUtils; /** * Injectable ordering of event plugins. */ var eventPluginOrder = null; /** * Injectable mapping from names to event plugin modules. */ var namesToPlugins = {}; /** * Recomputes the plugin list using the injected plugins and plugin ordering. * * @private */ function recomputePluginOrdering() { if (!eventPluginOrder) { // Wait until an `eventPluginOrder` is injected. return; } for (var pluginName in namesToPlugins) { var pluginModule = namesToPlugins[pluginName]; var pluginIndex = eventPluginOrder.indexOf(pluginName); !(pluginIndex > -1) ? invariant(false, 'EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `%s`.', pluginName) : void 0; if (EventPluginRegistry.plugins[pluginIndex]) { continue; } !pluginModule.extractEvents ? invariant(false, 'EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `%s` does not.', pluginName) : void 0; EventPluginRegistry.plugins[pluginIndex] = pluginModule; var publishedEvents = pluginModule.eventTypes; for (var eventName in publishedEvents) { !publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName) ? invariant(false, 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', eventName, pluginName) : void 0; } } } /** * Publishes an event so that it can be dispatched by the supplied plugin. * * @param {object} dispatchConfig Dispatch configuration for the event. * @param {object} PluginModule Plugin publishing the event. * @return {boolean} True if the event was successfully published. * @private */ function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { !!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName) ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.', eventName) : void 0; EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig; var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; if (phasedRegistrationNames) { for (var phaseName in phasedRegistrationNames) { if (phasedRegistrationNames.hasOwnProperty(phaseName)) { var phasedRegistrationName = phasedRegistrationNames[phaseName]; publishRegistrationName(phasedRegistrationName, pluginModule, eventName); } } return true; } else if (dispatchConfig.registrationName) { publishRegistrationName(dispatchConfig.registrationName, pluginModule, eventName); return true; } return false; } /** * Publishes a registration name that is used to identify dispatched events. * * @param {string} registrationName Registration name to add. * @param {object} PluginModule Plugin publishing the event. * @private */ function publishRegistrationName(registrationName, pluginModule, eventName) { !!EventPluginRegistry.registrationNameModules[registrationName] ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.', registrationName) : void 0; EventPluginRegistry.registrationNameModules[registrationName] = pluginModule; EventPluginRegistry.registrationNameDependencies[registrationName] = pluginModule.eventTypes[eventName].dependencies; { var lowerCasedName = registrationName.toLowerCase(); EventPluginRegistry.possibleRegistrationNames[lowerCasedName] = registrationName; if (registrationName === 'onDoubleClick') { EventPluginRegistry.possibleRegistrationNames.ondblclick = registrationName; } } } /** * Registers plugins so that they can extract and dispatch events. * * @see {EventPluginHub} */ var EventPluginRegistry = { /** * Ordered list of injected plugins. */ plugins: [], /** * Mapping from event name to dispatch config */ eventNameDispatchConfigs: {}, /** * Mapping from registration name to plugin module */ registrationNameModules: {}, /** * Mapping from registration name to event name */ registrationNameDependencies: {}, /** * Mapping from lowercase registration names to the properly cased version, * used to warn in the case of missing event handlers. Available * only in true. * @type {Object} */ possibleRegistrationNames: {}, // Trust the developer to only use possibleRegistrationNames in true /** * Injects an ordering of plugins (by plugin name). This allows the ordering * to be decoupled from injection of the actual plugins so that ordering is * always deterministic regardless of packaging, on-the-fly injection, etc. * * @param {array} InjectedEventPluginOrder * @internal * @see {EventPluginHub.injection.injectEventPluginOrder} */ injectEventPluginOrder: function (injectedEventPluginOrder) { !!eventPluginOrder ? invariant(false, 'EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React.') : void 0; // Clone the ordering so it cannot be dynamically mutated. eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); recomputePluginOrdering(); }, /** * Injects plugins to be used by `EventPluginHub`. The plugin names must be * in the ordering injected by `injectEventPluginOrder`. * * Plugins can be injected as part of page initialization or on-the-fly. * * @param {object} injectedNamesToPlugins Map from names to plugin modules. * @internal * @see {EventPluginHub.injection.injectEventPluginsByName} */ injectEventPluginsByName: function (injectedNamesToPlugins) { var isOrderingDirty = false; for (var pluginName in injectedNamesToPlugins) { if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { continue; } var pluginModule = injectedNamesToPlugins[pluginName]; if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== pluginModule) { !!namesToPlugins[pluginName] ? invariant(false, 'EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.', pluginName) : void 0; namesToPlugins[pluginName] = pluginModule; isOrderingDirty = true; } } if (isOrderingDirty) { recomputePluginOrdering(); } } }; var EventPluginRegistry_1 = EventPluginRegistry; /** * Accumulates items that must not be null or undefined into the first one. This * is used to conserve memory by avoiding array allocations, and thus sacrifices * API cleanness. Since `current` can be null before being passed in and not * null after this function, make sure to assign it back to `current`: * * `a = accumulateInto(a, b);` * * This API should be sparingly used. Try `accumulate` for something cleaner. * * @return {*|array<*>} An accumulation of items. */ function accumulateInto(current, next) { !(next != null) ? invariant(false, 'accumulateInto(...): Accumulated items must not be null or undefined.') : void 0; if (current == null) { return next; } // Both are not empty. Warning: Never call x.concat(y) when you are not // certain that x is an Array (x could be a string with concat method). if (Array.isArray(current)) { if (Array.isArray(next)) { current.push.apply(current, next); return current; } current.push(next); return current; } if (Array.isArray(next)) { // A bit too dangerous to mutate `next`. return [current].concat(next); } return [current, next]; } var accumulateInto_1 = accumulateInto; /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @providesModule forEachAccumulated * */ /** * @param {array} arr an "accumulation" of items which is either an Array or * a single item. Useful when paired with the `accumulate` module. This is a * simple utility that allows us to reason about a collection of items, but * handling the case when there is exactly one item (and we do not need to * allocate an array). * @param {function} cb Callback invoked with each element or a collection. * @param {?} [scope] Scope used as `this` in a callback. */ function forEachAccumulated(arr, cb, scope) { if (Array.isArray(arr)) { arr.forEach(cb, scope); } else if (arr) { cb.call(scope, arr); } } var forEachAccumulated_1 = forEachAccumulated; /** * Internal queue of events that have accumulated their dispatches and are * waiting to have their dispatches executed. */ var eventQueue = null; /** * Dispatches an event and releases it back into the pool, unless persistent. * * @param {?object} event Synthetic event to be dispatched. * @param {boolean} simulated If the event is simulated (changes exn behavior) * @private */ var executeDispatchesAndRelease = function (event, simulated) { if (event) { EventPluginUtils_1.executeDispatchesInOrder(event, simulated); if (!event.isPersistent()) { event.constructor.release(event); } } }; var executeDispatchesAndReleaseSimulated = function (e) { return executeDispatchesAndRelease(e, true); }; var executeDispatchesAndReleaseTopLevel = function (e) { return executeDispatchesAndRelease(e, false); }; function isInteractive(tag) { return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea'; } function shouldPreventMouseEvent(name, type, props) { switch (name) { case 'onClick': case 'onClickCapture': case 'onDoubleClick': case 'onDoubleClickCapture': case 'onMouseDown': case 'onMouseDownCapture': case 'onMouseMove': case 'onMouseMoveCapture': case 'onMouseUp': case 'onMouseUpCapture': return !!(props.disabled && isInteractive(type)); default: return false; } } /** * This is a unified interface for event plugins to be installed and configured. * * Event plugins can implement the following properties: * * `extractEvents` {function(string, DOMEventTarget, string, object): *} * Required. When a top-level event is fired, this method is expected to * extract synthetic events that will in turn be queued and dispatched. * * `eventTypes` {object} * Optional, plugins that fire events must publish a mapping of registration * names that are used to register listeners. Values of this mapping must * be objects that contain `registrationName` or `phasedRegistrationNames`. * * `executeDispatch` {function(object, function, string)} * Optional, allows plugins to override how an event gets dispatched. By * default, the listener is simply invoked. * * Each plugin that is injected into `EventsPluginHub` is immediately operable. * * @public */ var EventPluginHub = { /** * Methods for injecting dependencies. */ injection: { /** * @param {array} InjectedEventPluginOrder * @public */ injectEventPluginOrder: EventPluginRegistry_1.injectEventPluginOrder, /** * @param {object} injectedNamesToPlugins Map from names to plugin modules. */ injectEventPluginsByName: EventPluginRegistry_1.injectEventPluginsByName }, /** * @param {object} inst The instance, which is the source of events. * @param {string} registrationName Name of listener (e.g. `onClick`). * @return {?function} The stored callback. */ getListener: function (inst, registrationName) { var listener; // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not // live here; needs to be moved to a better place soon if (typeof inst.tag === 'number') { var stateNode = inst.stateNode; if (!stateNode) { // Work in progress (ex: onload events in incremental mode). return null; } var props = EventPluginUtils_1.getFiberCurrentPropsFromNode(stateNode); if (!props) { // Work in progress. return null; } listener = props[registrationName]; if (shouldPreventMouseEvent(registrationName, inst.type, props)) { return null; } } else { var currentElement = inst._currentElement; if (typeof currentElement === 'string' || typeof currentElement === 'number') { // Text node, let it bubble through. return null; } if (!inst._rootNodeID) { // If the instance is already unmounted, we have no listeners. return null; } var _props = currentElement.props; listener = _props[registrationName]; if (shouldPreventMouseEvent(registrationName, currentElement.type, _props)) { return null; } } !(!listener || typeof listener === 'function') ? invariant(false, 'Expected `%s` listener to be a function, instead got a value of `%s` type.', registrationName, typeof listener) : void 0; return listener; }, /** * Allows registered plugins an opportunity to extract events from top-level * native browser events. * * @return {*} An accumulation of synthetic events. * @internal */ extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { var events; var plugins = EventPluginRegistry_1.plugins; for (var i = 0; i < plugins.length; i++) { // Not every plugin in the ordering may be loaded at runtime. var possiblePlugin = plugins[i]; if (possiblePlugin) { var extractedEvents = possiblePlugin.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); if (extractedEvents) { events = accumulateInto_1(events, extractedEvents); } } } return events; }, /** * Enqueues a synthetic event that should be dispatched when * `processEventQueue` is invoked. * * @param {*} events An accumulation of synthetic events. * @internal */ enqueueEvents: function (events) { if (events) { eventQueue = accumulateInto_1(eventQueue, events); } }, /** * Dispatches all synthetic events on the event queue. * * @internal */ processEventQueue: function (simulated) { // Set `eventQueue` to null before processing it so that we can tell if more // events get enqueued while processing. var processingEventQueue = eventQueue; eventQueue = null; if (simulated) { forEachAccumulated_1(processingEventQueue, executeDispatchesAndReleaseSimulated); } else { forEachAccumulated_1(processingEventQueue, executeDispatchesAndReleaseTopLevel); } !!eventQueue ? invariant(false, 'processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented.') : void 0; // This would be a good time to rethrow if any of the event handlers threw. ReactErrorUtils_1.rethrowCaughtError(); } }; var EventPluginHub_1 = EventPluginHub; /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @providesModule ReactTypeOfWork * */ var ReactTypeOfWork = { IndeterminateComponent: 0, // Before we know whether it is functional or class FunctionalComponent: 1, ClassComponent: 2, HostRoot: 3, // Root of a host tree. Could be nested inside another node. HostPortal: 4, // A subtree. Could be an entry point to a different renderer. HostComponent: 5, HostText: 6, CoroutineComponent: 7, CoroutineHandlerPhase: 8, YieldComponent: 9, Fragment: 10 }; var HostComponent = ReactTypeOfWork.HostComponent; function getParent(inst) { if (inst._hostParent !== undefined) { return inst._hostParent; } if (typeof inst.tag === 'number') { do { inst = inst['return']; // TODO: If this is a HostRoot we might want to bail out. // That is depending on if we want nested subtrees (layers) to bubble // events to their parent. We could also go through parentNode on the // host node but that wouldn't work for React Native and doesn't let us // do the portal feature. } while (inst && inst.tag !== HostComponent); if (inst) { return inst; } } return null; } /** * Return the lowest common ancestor of A and B, or null if they are in * different trees. */ function getLowestCommonAncestor(instA, instB) { var depthA = 0; for (var tempA = instA; tempA; tempA = getParent(tempA)) { depthA++; } var depthB = 0; for (var tempB = instB; tempB; tempB = getParent(tempB)) { depthB++; } // If A is deeper, crawl up. while (depthA - depthB > 0) { instA = getParent(instA); depthA--; } // If B is deeper, crawl up. while (depthB - depthA > 0) { instB = getParent(instB); depthB--; } // Walk in lockstep until we find a match. var depth = depthA; while (depth--) { if (instA === instB || instA === instB.alternate) { return instA; } instA = getParent(instA); instB = getParent(instB); } return null; } /** * Return if A is an ancestor of B. */ function isAncestor(instA, instB) { while (instB) { if (instA === instB || instA === instB.alternate) { return true; } instB = getParent(instB); } return false; } /** * Return the parent instance of the passed-in instance. */ function getParentInstance(inst) { return getParent(inst); } /** * Simulates the traversal of a two-phase, capture/bubble event dispatch. */ function traverseTwoPhase(inst, fn, arg) { var path = []; while (inst) { path.push(inst); inst = getParent(inst); } var i; for (i = path.length; i-- > 0;) { fn(path[i], 'captured', arg); } for (i = 0; i < path.length; i++) { fn(path[i], 'bubbled', arg); } } /** * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that * should would receive a `mouseEnter` or `mouseLeave` event. * * Does not invoke the callback on the nearest common ancestor because nothing * "entered" or "left" that element. */ function traverseEnterLeave(from, to, fn, argFrom, argTo) { var common = from && to ? getLowestCommonAncestor(from, to) : null; var pathFrom = []; while (from && from !== common) { pathFrom.push(from); from = getParent(from); } var pathTo = []; while (to && to !== common) { pathTo.push(to); to = getParent(to); } var i; for (i = 0; i < pathFrom.length; i++) { fn(pathFrom[i], 'bubbled', argFrom); } for (i = pathTo.length; i-- > 0;) { fn(pathTo[i], 'captured', argTo); } } var ReactTreeTraversal = { isAncestor: isAncestor, getLowestCommonAncestor: getLowestCommonAncestor, getParentInstance: getParentInstance, traverseTwoPhase: traverseTwoPhase, traverseEnterLeave: traverseEnterLeave }; var getListener = EventPluginHub_1.getListener; { var warning$1 = require$$0; } /** * Some event types have a notion of different registration names for different * "phases" of propagation. This finds listeners by a given phase. */ function listenerAtPhase(inst, event, propagationPhase) { var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; return getListener(inst, registrationName); } /** * Tags a `SyntheticEvent` with dispatched listeners. Creating this function * here, allows us to not have to bind or create functions for each event. * Mutating the event's members allows us to not have to create a wrapping * "dispatch" object that pairs the event with the listener. */ function accumulateDirectionalDispatches(inst, phase, event) { { warning$1(inst, 'Dispatching inst must not be null'); } var listener = listenerAtPhase(inst, event, phase); if (listener) { event._dispatchListeners = accumulateInto_1(event._dispatchListeners, listener); event._dispatchInstances = accumulateInto_1(event._dispatchInstances, inst); } } /** * Collect dispatches (must be entirely collected before dispatching - see unit * tests). Lazily allocate the array to conserve memory. We must loop through * each event and perform the traversal for each one. We cannot perform a * single traversal for the entire collection of events because each event may * have a different target. */ function accumulateTwoPhaseDispatchesSingle(event) { if (event && event.dispatchConfig.phasedRegistrationNames) { ReactTreeTraversal.traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); } } /** * Same as `accumulateTwoPhaseDispatchesSingle`, but skips over the targetID. */ function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { if (event && event.dispatchConfig.phasedRegistrationNames) { var targetInst = event._targetInst; var parentInst = targetInst ? ReactTreeTraversal.getParentInstance(targetInst) : null; ReactTreeTraversal.traverseTwoPhase(parentInst, accumulateDirectionalDispatches, event); } } /** * Accumulates without regard to direction, does not look for phased * registration names. Same as `accumulateDirectDispatchesSingle` but without * requiring that the `dispatchMarker` be the same as the dispatched ID. */ function accumulateDispatches(inst, ignoredDirection, event) { if (inst && event && event.dispatchConfig.registrationName) { var registrationName = event.dispatchConfig.registrationName; var listener = getListener(inst, registrationName); if (listener) { event._dispatchListeners = accumulateInto_1(event._dispatchListeners, listener); event._dispatchInstances = accumulateInto_1(event._dispatchInstances, inst); } } } /** * Accumulates dispatches on an `SyntheticEvent`, but only for the * `dispatchMarker`. * @param {SyntheticEvent} event */ function accumulateDirectDispatchesSingle(event) { if (event && event.dispatchConfig.registrationName) { accumulateDispatches(event._targetInst, null, event); } } function accumulateTwoPhaseDispatches(events) { forEachAccumulated_1(events, accumulateTwoPhaseDispatchesSingle); } function accumulateTwoPhaseDispatchesSkipTarget(events) { forEachAccumulated_1(events, accumulateTwoPhaseDispatchesSingleSkipTarget); } function accumulateEnterLeaveDispatches(leave, enter, from, to) { ReactTreeTraversal.traverseEnterLeave(from, to, accumulateDispatches, leave, enter); } function accumulateDirectDispatches(events) { forEachAccumulated_1(events, accumulateDirectDispatchesSingle); } /** * A small set of propagation patterns, each of which will accept a small amount * of information, and generate a set of "dispatch ready event objects" - which * are sets of events that have already been annotated with a set of dispatched * listener functions/ids. The API is designed this way to discourage these * propagation strategies from actually executing the dispatches, since we * always want to collect the entire set of dispatches before executing even a * single one. * * @constructor EventPropagators */ var EventPropagators = { accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches, accumulateTwoPhaseDispatchesSkipTarget: accumulateTwoPhaseDispatchesSkipTarget, accumulateDirectDispatches: accumulateDirectDispatches, accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches }; var EventPropagators_1 = EventPropagators; var didWarnForAddedNewProperty = false; var isProxySupported = typeof Proxy === 'function'; var EVENT_POOL_SIZE = 10; { var warning$2 = require$$0; } var shouldBeReleasedProperties = ['dispatchConfig', '_targetInst', 'nativeEvent', 'isDefaultPrevented', 'isPropagationStopped', '_dispatchListeners', '_dispatchInstances']; /** * @interface Event * @see http://www.w3.org/TR/DOM-Level-3-Events/ */ var EventInterface = { type: null, target: null, // currentTarget is set when dispatching; no use in copying it here currentTarget: emptyFunction.thatReturnsNull, eventPhase: null, bubbles: null, cancelable: null, timeStamp: function (event) { return event.timeStamp || Date.now(); }, defaultPrevented: null, isTrusted: null }; /** * Synthetic events are dispatched by event plugins, typically in response to a * top-level event delegation handler. * * These systems should generally use pooling to reduce the frequency of garbage * collection. The system should check `isPersistent` to determine whether the * event should be released into the pool after being dispatched. Users that * need a persisted event should invoke `persist`. * * Synthetic events (and subclasses) implement the DOM Level 3 Events API by * normalizing browser quirks. Subclasses do not necessarily have to implement a * DOM interface; custom application-specific events can also subclass this. * * @param {object} dispatchConfig Configuration used to dispatch this event. * @param {*} targetInst Marker identifying the event target. * @param {object} nativeEvent Native browser event. * @param {DOMEventTarget} nativeEventTarget Target node. */ function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) { { // these have a getter/setter for warnings delete this.nativeEvent; delete this.preventDefault; delete this.stopPropagation; } this.dispatchConfig = dispatchConfig; this._targetInst = targetInst; this.nativeEvent = nativeEvent; var Interface = this.constructor.Interface; for (var propName in Interface) { if (!Interface.hasOwnProperty(propName)) { continue; } { delete this[propName]; // this has a getter/setter for warnings } var normalize = Interface[propName]; if (normalize) { this[propName] = normalize(nativeEvent); } else { if (propName === 'target') { this.target = nativeEventTarget; } else { this[propName] = nativeEvent[propName]; } } } var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false; if (defaultPrevented) { this.isDefaultPrevented = emptyFunction.thatReturnsTrue; } else { this.isDefaultPrevented = emptyFunction.thatReturnsFalse; } this.isPropagationStopped = emptyFunction.thatReturnsFalse; return this; } objectAssign$1(SyntheticEvent.prototype, { preventDefault: function () { this.defaultPrevented = true; var event = this.nativeEvent; if (!event) { return; } if (event.preventDefault) { event.preventDefault(); } else if (typeof event.returnValue !== 'unknown') { event.returnValue = false; } this.isDefaultPrevented = emptyFunction.thatReturnsTrue; }, stopPropagation: function () { var event = this.nativeEvent; if (!event) { return; } if (event.stopPropagation) { event.stopPropagation(); } else if (typeof event.cancelBubble !== 'unknown') { // The ChangeEventPlugin registers a "propertychange" event for // IE. This event does not support bubbling or cancelling, and // any references to cancelBubble throw "Member not found". A // typeof check of "unknown" circumvents this issue (and is also // IE specific). event.cancelBubble = true; } this.isPropagationStopped = emptyFunction.thatReturnsTrue; }, /** * We release all dispatched `SyntheticEvent`s after each event loop, adding * them back into the pool. This allows a way to hold onto a reference that * won't be added back into the pool. */ persist: function () { this.isPersistent = emptyFunction.thatReturnsTrue; }, /** * Checks if this event should be released back into the pool. * * @return {boolean} True if this should not be released, false otherwise. */ isPersistent: emptyFunction.thatReturnsFalse, /** * `PooledClass` looks for `destructor` on each instance it releases. */ destructor: function () { var Interface = this.constructor.Interface; for (var propName in Interface) { { Object.defineProperty(this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName])); } } for (var i = 0; i < shouldBeReleasedProperties.length; i++) { this[shouldBeReleasedProperties[i]] = null; } { Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null)); Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', emptyFunction)); Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', emptyFunction)); } } }); SyntheticEvent.Interface = EventInterface; /** * Helper to reduce boilerplate when creating subclasses. * * @param {function} Class * @param {?object} Interface */ SyntheticEvent.augmentClass = function (Class, Interface) { var Super = this; var E = function () {}; E.prototype = Super.prototype; var prototype = new E(); objectAssign$1(prototype, Class.prototype); Class.prototype = prototype; Class.prototype.constructor = Class; Class.Interface = objectAssign$1({}, Super.Interface, Interface); Class.augmentClass = Super.augmentClass; addEventPoolingTo(Class); }; /** Proxying after everything set on SyntheticEvent * to resolve Proxy issue on some WebKit browsers * in which some Event properties are set to undefined (GH#10010) */ { if (isProxySupported) { /*eslint-disable no-func-assign */ SyntheticEvent = new Proxy(SyntheticEvent, { construct: function (target, args) { return this.apply(target, Object.create(target.prototype), args); }, apply: function (constructor, that, args) { return new Proxy(constructor.apply(that, args), { set: function (target, prop, value) { if (prop !== 'isPersistent' && !target.constructor.Interface.hasOwnProperty(prop) && shouldBeReleasedProperties.indexOf(prop) === -1) { warning$2(didWarnForAddedNewProperty || target.isPersistent(), "This synthetic event is reused for performance reasons. If you're " + "seeing this, you're adding a new property in the synthetic event object. " + 'The property is never released. See ' + 'https://fb.me/react-event-pooling for more information.'); didWarnForAddedNewProperty = true; } target[prop] = value; return true; } }); } }); /*eslint-enable no-func-assign */ } } addEventPoolingTo(SyntheticEvent); var SyntheticEvent_1 = SyntheticEvent; /** * Helper to nullify syntheticEvent instance properties when destructing * * @param {String} propName * @param {?object} getVal * @return {object} defineProperty object */ function getPooledWarningPropertyDefinition(propName, getVal) { var isFunction = typeof getVal === 'function'; return { configurable: true, set: set, get: get }; function set(val) { var action = isFunction ? 'setting the method' : 'setting the property'; warn(action, 'This is effectively a no-op'); return val; } function get() { var action = isFunction ? 'accessing the method' : 'accessing the property'; var result = isFunction ? 'This is a no-op function' : 'This is set to null'; warn(action, result); return getVal; } function warn(action, result) { var warningCondition = false; warning$2(warningCondition, "This synthetic event is reused for performance reasons. If you're seeing this, " + "you're %s `%s` on a released/nullified synthetic event. %s. " + 'If you must keep the original synthetic event around, use event.persist(). ' + 'See https://fb.me/react-event-pooling for more information.', action, propName, result); } } function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { var EventConstructor = this; if (EventConstructor.eventPool.length) { var instance = EventConstructor.eventPool.pop(); EventConstructor.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); return instance; } return new EventConstructor(dispatchConfig, targetInst, nativeEvent, nativeInst); } function releasePooledEvent(event) { var EventConstructor = this; !(event instanceof EventConstructor) ? invariant(false, 'Trying to release an event instance into a pool of a different type.') : void 0; event.destructor(); if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { EventConstructor.eventPool.push(event); } } function addEventPoolingTo(EventConstructor) { EventConstructor.eventPool = []; EventConstructor.getPooled = getPooledEvent; EventConstructor.release = releasePooledEvent; } /** * `touchHistory` isn't actually on the native event, but putting it in the * interface will ensure that it is cleaned up when pooled/destroyed. The * `ResponderEventPlugin` will populate it appropriately. */ var ResponderEventInterface = { touchHistory: function (nativeEvent) { return null; // Actually doesn't even look at the native event. } }; /** * @param {object} dispatchConfig Configuration used to dispatch this event. * @param {string} dispatchMarker Marker identifying the event target. * @param {object} nativeEvent Native event. * @extends {SyntheticEvent} */ function ResponderSyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { return SyntheticEvent_1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } SyntheticEvent_1.augmentClass(ResponderSyntheticEvent, ResponderEventInterface); var ResponderSyntheticEvent_1 = ResponderSyntheticEvent; var isEndish$2 = EventPluginUtils_1.isEndish; var isMoveish$2 = EventPluginUtils_1.isMoveish; var isStartish$2 = EventPluginUtils_1.isStartish; { var warning$3 = require$$0; } /** * Tracks the position and time of each active touch by `touch.identifier`. We * should typically only see IDs in the range of 1-20 because IDs get recycled * when touches end and start again. */ var MAX_TOUCH_BANK = 20; var touchBank = []; var touchHistory = { touchBank: touchBank, numberActiveTouches: 0, // If there is only one active touch, we remember its location. This prevents // us having to loop through all of the touches all the time in the most // common case. indexOfSingleActiveTouch: -1, mostRecentTimeStamp: 0 }; function timestampForTouch(touch) { // The legacy internal implementation provides "timeStamp", which has been // renamed to "timestamp". Let both work for now while we iron it out // TODO (evv): rename timeStamp to timestamp in internal code return touch.timeStamp || touch.timestamp; } /** * TODO: Instead of making gestures recompute filtered velocity, we could * include a built in velocity computation that can be reused globally. */ function createTouchRecord(touch) { return { touchActive: true, startPageX: touch.pageX, startPageY: touch.pageY, startTimeStamp: timestampForTouch(touch), currentPageX: touch.pageX, currentPageY: touch.pageY, currentTimeStamp: timestampForTouch(touch), previousPageX: touch.pageX, previousPageY: touch.pageY, previousTimeStamp: timestampForTouch(touch) }; } function resetTouchRecord(touchRecord, touch) { touchRecord.touchActive = true; touchRecord.startPageX = touch.pageX; touchRecord.startPageY = touch.pageY; touchRecord.startTimeStamp = timestampForTouch(touch); touchRecord.currentPageX = touch.pageX; touchRecord.currentPageY = touch.pageY; touchRecord.currentTimeStamp = timestampForTouch(touch); touchRecord.previousPageX = touch.pageX; touchRecord.previousPageY = touch.pageY; touchRecord.previousTimeStamp = timestampForTouch(touch); } function getTouchIdentifier(_ref) { var identifier = _ref.identifier; !(identifier != null) ? invariant(false, 'Touch object is missing identifier.') : void 0; { warning$3(identifier <= MAX_TOUCH_BANK, 'Touch identifier %s is greater than maximum supported %s which causes ' + 'performance issues backfilling array locations for all of the indices.', identifier, MAX_TOUCH_BANK); } return identifier; } function recordTouchStart(touch) { var identifier = getTouchIdentifier(touch); var touchRecord = touchBank[identifier]; if (touchRecord) { resetTouchRecord(touchRecord, touch); } else { touchBank[identifier] = createTouchRecord(touch); } touchHistory.mostRecentTimeStamp = timestampForTouch(touch); } function recordTouchMove(touch) { var touchRecord = touchBank[getTouchIdentifier(touch)]; if (touchRecord) { touchRecord.touchActive = true; touchRecord.previousPageX = touchRecord.currentPageX; touchRecord.previousPageY = touchRecord.currentPageY; touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; touchRecord.currentPageX = touch.pageX; touchRecord.currentPageY = touch.pageY; touchRecord.currentTimeStamp = timestampForTouch(touch); touchHistory.mostRecentTimeStamp = timestampForTouch(touch); } else { console.error('Cannot record touch move without a touch start.\n' + 'Touch Move: %s\n', 'Touch Bank: %s', printTouch(touch), printTouchBank()); } } function recordTouchEnd(touch) { var touchRecord = touchBank[getTouchIdentifier(touch)]; if (touchRecord) { touchRecord.touchActive = false; touchRecord.previousPageX = touchRecord.currentPageX; touchRecord.previousPageY = touchRecord.currentPageY; touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; touchRecord.currentPageX = touch.pageX; touchRecord.currentPageY = touch.pageY; touchRecord.currentTimeStamp = timestampForTouch(touch); touchHistory.mostRecentTimeStamp = timestampForTouch(touch); } else { console.error('Cannot record touch end without a touch start.\n' + 'Touch End: %s\n', 'Touch Bank: %s', printTouch(touch), printTouchBank()); } } function printTouch(touch) { return JSON.stringify({ identifier: touch.identifier, pageX: touch.pageX, pageY: touch.pageY, timestamp: timestampForTouch(touch) }); } function printTouchBank() { var printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK)); if (touchBank.length > MAX_TOUCH_BANK) { printed += ' (original size: ' + touchBank.length + ')'; } return printed; } var ResponderTouchHistoryStore = { recordTouchTrack: function (topLevelType, nativeEvent) { if (isMoveish$2(topLevelType)) { nativeEvent.changedTouches.forEach(recordTouchMove); } else if (isStartish$2(topLevelType)) { nativeEvent.changedTouches.forEach(recordTouchStart); touchHistory.numberActiveTouches = nativeEvent.touches.length; if (touchHistory.numberActiveTouches === 1) { touchHistory.indexOfSingleActiveTouch = nativeEvent.touches[0].identifier; } } else if (isEndish$2(topLevelType)) { nativeEvent.changedTouches.forEach(recordTouchEnd); touchHistory.numberActiveTouches = nativeEvent.touches.length; if (touchHistory.numberActiveTouches === 1) { for (var i = 0; i < touchBank.length; i++) { var touchTrackToCheck = touchBank[i]; if (touchTrackToCheck != null && touchTrackToCheck.touchActive) { touchHistory.indexOfSingleActiveTouch = i; break; } } { var activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch]; warning$3(activeRecord != null && activeRecord.touchActive, 'Cannot find single active touch.'); } } } }, touchHistory: touchHistory }; var ResponderTouchHistoryStore_1 = ResponderTouchHistoryStore; /** * Accumulates items that must not be null or undefined. * * This is used to conserve memory by avoiding array allocations. * * @return {*|array<*>} An accumulation of items. */ function accumulate(current, next) { !(next != null) ? invariant(false, 'accumulate(...): Accumulated items must be not be null or undefined.') : void 0; if (current == null) { return next; } // Both are not empty. Warning: Never call x.concat(y) when you are not // certain that x is an Array (x could be a string with concat method). if (Array.isArray(current)) { return current.concat(next); } if (Array.isArray(next)) { return [current].concat(next); } return [current, next]; } var accumulate_1 = accumulate; var isStartish$1 = EventPluginUtils_1.isStartish; var isMoveish$1 = EventPluginUtils_1.isMoveish; var isEndish$1 = EventPluginUtils_1.isEndish; var executeDirectDispatch$1 = EventPluginUtils_1.executeDirectDispatch; var hasDispatches$1 = EventPluginUtils_1.hasDispatches; var executeDispatchesInOrderStopAtTrue$1 = EventPluginUtils_1.executeDispatchesInOrderStopAtTrue; /** * Instance of element that should respond to touch/move types of interactions, * as indicated explicitly by relevant callbacks. */ var responderInst = null; /** * Count of current touches. A textInput should become responder iff the * selection changes while there is a touch on the screen. */ var trackedTouchCount = 0; /** * Last reported number of active touches. */ var previousActiveTouches = 0; var changeResponder = function (nextResponderInst, blockHostResponder) { var oldResponderInst = responderInst; responderInst = nextResponderInst; if (ResponderEventPlugin.GlobalResponderHandler !== null) { ResponderEventPlugin.GlobalResponderHandler.onChange(oldResponderInst, nextResponderInst, blockHostResponder); } }; var eventTypes = { /** * On a `touchStart`/`mouseDown`, is it desired that this element become the * responder? */ startShouldSetResponder: { phasedRegistrationNames: { bubbled: 'onStartShouldSetResponder', captured: 'onStartShouldSetResponderCapture' } }, /** * On a `scroll`, is it desired that this element become the responder? This * is usually not needed, but should be used to retroactively infer that a * `touchStart` had occurred during momentum scroll. During a momentum scroll, * a touch start will be immediately followed by a scroll event if the view is * currently scrolling. * * TODO: This shouldn't bubble. */ scrollShouldSetResponder: { phasedRegistrationNames: { bubbled: 'onScrollShouldSetResponder', captured: 'onScrollShouldSetResponderCapture' } }, /** * On text selection change, should this element become the responder? This * is needed for text inputs or other views with native selection, so the * JS view can claim the responder. * * TODO: This shouldn't bubble. */ selectionChangeShouldSetResponder: { phasedRegistrationNames: { bubbled: 'onSelectionChangeShouldSetResponder', captured: 'onSelectionChangeShouldSetResponderCapture' } }, /** * On a `touchMove`/`mouseMove`, is it desired that this element become the * responder? */ moveShouldSetResponder: { phasedRegistrationNames: { bubbled: 'onMoveShouldSetResponder', captured: 'onMoveShouldSetResponderCapture' } }, /** * Direct responder events dispatched directly to responder. Do not bubble. */ responderStart: { registrationName: 'onResponderStart' }, responderMove: { registrationName: 'onResponderMove' }, responderEnd: { registrationName: 'onResponderEnd' }, responderRelease: { registrationName: 'onResponderRelease' }, responderTerminationRequest: { registrationName: 'onResponderTerminationRequest' }, responderGrant: { registrationName: 'onResponderGrant' }, responderReject: { registrationName: 'onResponderReject' }, responderTerminate: { registrationName: 'onResponderTerminate' } }; /** * * Responder System: * ---------------- * * - A global, solitary "interaction lock" on a view. * - If a node becomes the responder, it should convey visual feedback * immediately to indicate so, either by highlighting or moving accordingly. * - To be the responder means, that touches are exclusively important to that * responder view, and no other view. * - While touches are still occurring, the responder lock can be transferred to * a new view, but only to increasingly "higher" views (meaning ancestors of * the current responder). * * Responder being granted: * ------------------------ * * - Touch starts, moves, and scrolls can cause an ID to become the responder. * - We capture/bubble `startShouldSetResponder`/`moveShouldSetResponder` to * the "appropriate place". * - If nothing is currently the responder, the "appropriate place" is the * initiating event's `targetID`. * - If something *is* already the responder, the "appropriate place" is the * first common ancestor of the event target and the current `responderInst`. * - Some negotiation happens: See the timing diagram below. * - Scrolled views automatically become responder. The reasoning is that a * platform scroll view that isn't built on top of the responder system has * began scrolling, and the active responder must now be notified that the * interaction is no longer locked to it - the system has taken over. * * - Responder being released: * As soon as no more touches that *started* inside of descendants of the * *current* responderInst, an `onResponderRelease` event is dispatched to the * current responder, and the responder lock is released. * * TODO: * - on "end", a callback hook for `onResponderEndShouldRemainResponder` that * determines if the responder lock should remain. * - If a view shouldn't "remain" the responder, any active touches should by * default be considered "dead" and do not influence future negotiations or * bubble paths. It should be as if those touches do not exist. * -- For multitouch: Usually a translate-z will choose to "remain" responder * after one out of many touches ended. For translate-y, usually the view * doesn't wish to "remain" responder after one of many touches end. * - Consider building this on top of a `stopPropagation` model similar to * `W3C` events. * - Ensure that `onResponderTerminate` is called on touch cancels, whether or * not `onResponderTerminationRequest` returns `true` or `false`. * */ /* Negotiation Performed +-----------------------+ / \ Process low level events to + Current Responder + wantsResponderID determine who to perform negot-| (if any exists at all) | iation/transition | Otherwise just pass through| -------------------------------+----------------------------+------------------+ Bubble to find first ID | | to return true:wantsResponderID| | | | +-------------+ | | | onTouchStart| | | +------+------+ none | | | return| | +-----------v-------------+true| +------------------------+ | |onStartShouldSetResponder|----->|onResponderStart (cur) |<-----------+ +-----------+-------------+ | +------------------------+ | | | | | +--------+-------+ | returned true for| false:REJECT +-------->|onResponderReject | wantsResponderID | | | +----------------+ | (now attempt | +------------------+-----+ | | handoff) | | onResponder | | +------------------->| TerminationRequest| | | +------------------+-----+ | | | | +----------------+ | true:GRANT +-------->|onResponderGrant| | | +--------+-------+ | +------------------------+ | | | | onResponderTerminate |<-----------+ | +------------------+-----+ | | | | +----------------+ | +-------->|onResponderStart| | | +----------------+ Bubble to find first ID | | to return true:wantsResponderID| | | | +-------------+ | | | onTouchMove | | | +------+------+ none | | | return| | +-----------v-------------+true| +------------------------+ | |onMoveShouldSetResponder |----->|onResponderMove (cur) |<-----------+ +-----------+-------------+ | +------------------------+ | | | | | +--------+-------+ | returned true for| false:REJECT +-------->|onResponderRejec| | wantsResponderID | | | +----------------+ | (now attempt | +------------------+-----+ | | handoff) | | onResponder | | +------------------->| TerminationRequest| | | +------------------+-----+ | | | | +----------------+ | true:GRANT +-------->|onResponderGrant| | | +--------+-------+ | +------------------------+ | | | | onResponderTerminate |<-----------+ | +------------------+-----+ | | | | +----------------+ | +-------->|onResponderMove | | | +----------------+ | | | | Some active touch started| | inside current responder | +------------------------+ | +------------------------->| onResponderEnd | | | | +------------------------+ | +---+---------+ | | | onTouchEnd | | | +---+---------+ | | | | +------------------------+ | +------------------------->| onResponderEnd | | No active touches started| +-----------+------------+ | inside current responder | | | | v | | +------------------------+ | | | onResponderRelease | | | +------------------------+ | | | + + */ /** * A note about event ordering in the `EventPluginHub`. * * Suppose plugins are injected in the following order: * * `[R, S, C]` * * To help illustrate the example, assume `S` is `SimpleEventPlugin` (for * `onClick` etc) and `R` is `ResponderEventPlugin`. * * "Deferred-Dispatched Events": * * - The current event plugin system will traverse the list of injected plugins, * in order, and extract events by collecting the plugin's return value of * `extractEvents()`. * - These events that are returned from `extractEvents` are "deferred * dispatched events". * - When returned from `extractEvents`, deferred-dispatched events contain an * "accumulation" of deferred dispatches. * - These deferred dispatches are accumulated/collected before they are * returned, but processed at a later time by the `EventPluginHub` (hence the * name deferred). * * In the process of returning their deferred-dispatched events, event plugins * themselves can dispatch events on-demand without returning them from * `extractEvents`. Plugins might want to do this, so that they can use event * dispatching as a tool that helps them decide which events should be extracted * in the first place. * * "On-Demand-Dispatched Events": * * - On-demand-dispatched events are not returned from `extractEvents`. * - On-demand-dispatched events are dispatched during the process of returning * the deferred-dispatched events. * - They should not have side effects. * - They should be avoided, and/or eventually be replaced with another * abstraction that allows event plugins to perform multiple "rounds" of event * extraction. * * Therefore, the sequence of event dispatches becomes: * * - `R`s on-demand events (if any) (dispatched by `R` on-demand) * - `S`s on-demand events (if any) (dispatched by `S` on-demand) * - `C`s on-demand events (if any) (dispatched by `C` on-demand) * - `R`s extracted events (if any) (dispatched by `EventPluginHub`) * - `S`s extracted events (if any) (dispatched by `EventPluginHub`) * - `C`s extracted events (if any) (dispatched by `EventPluginHub`) * * In the case of `ResponderEventPlugin`: If the `startShouldSetResponder` * on-demand dispatch returns `true` (and some other details are satisfied) the * `onResponderGrant` deferred dispatched event is returned from * `extractEvents`. The sequence of dispatch executions in this case * will appear as follows: * * - `startShouldSetResponder` (`ResponderEventPlugin` dispatches on-demand) * - `touchStartCapture` (`EventPluginHub` dispatches as usual) * - `touchStart` (`EventPluginHub` dispatches as usual) * - `responderGrant/Reject` (`EventPluginHub` dispatches as usual) */ function setResponderAndExtractTransfer(topLevelType, targetInst, nativeEvent, nativeEventTarget) { var shouldSetEventType = isStartish$1(topLevelType) ? eventTypes.startShouldSetResponder : isMoveish$1(topLevelType) ? eventTypes.moveShouldSetResponder : topLevelType === 'topSelectionChange' ? eventTypes.selectionChangeShouldSetResponder : eventTypes.scrollShouldSetResponder; // TODO: stop one short of the current responder. var bubbleShouldSetFrom = !responderInst ? targetInst : ReactTreeTraversal.getLowestCommonAncestor(responderInst, targetInst); // When capturing/bubbling the "shouldSet" event, we want to skip the target // (deepest ID) if it happens to be the current responder. The reasoning: // It's strange to get an `onMoveShouldSetResponder` when you're *already* // the responder. var skipOverBubbleShouldSetFrom = bubbleShouldSetFrom === responderInst; var shouldSetEvent = ResponderSyntheticEvent_1.getPooled(shouldSetEventType, bubbleShouldSetFrom, nativeEvent, nativeEventTarget); shouldSetEvent.touchHistory = ResponderTouchHistoryStore_1.touchHistory; if (skipOverBubbleShouldSetFrom) { EventPropagators_1.accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent); } else { EventPropagators_1.accumulateTwoPhaseDispatches(shouldSetEvent); } var wantsResponderInst = executeDispatchesInOrderStopAtTrue$1(shouldSetEvent); if (!shouldSetEvent.isPersistent()) { shouldSetEvent.constructor.release(shouldSetEvent); } if (!wantsResponderInst || wantsResponderInst === responderInst) { return null; } var extracted; var grantEvent = ResponderSyntheticEvent_1.getPooled(eventTypes.responderGrant, wantsResponderInst, nativeEvent, nativeEventTarget); grantEvent.touchHistory = ResponderTouchHistoryStore_1.touchHistory; EventPropagators_1.accumulateDirectDispatches(grantEvent); var blockHostResponder = executeDirectDispatch$1(grantEvent) === true; if (responderInst) { var terminationRequestEvent = ResponderSyntheticEvent_1.getPooled(eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget); terminationRequestEvent.touchHistory = ResponderTouchHistoryStore_1.touchHistory; EventPropagators_1.accumulateDirectDispatches(terminationRequestEvent); var shouldSwitch = !hasDispatches$1(terminationRequestEvent) || executeDirectDispatch$1(terminationRequestEvent); if (!terminationRequestEvent.isPersistent()) { terminationRequestEvent.constructor.release(terminationRequestEvent); } if (shouldSwitch) { var terminateEvent = ResponderSyntheticEvent_1.getPooled(eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget); terminateEvent.touchHistory = ResponderTouchHistoryStore_1.touchHistory; EventPropagators_1.accumulateDirectDispatches(terminateEvent); extracted = accumulate_1(extracted, [grantEvent, terminateEvent]); changeResponder(wantsResponderInst, blockHostResponder); } else { var rejectEvent = ResponderSyntheticEvent_1.getPooled(eventTypes.responderReject, wantsResponderInst, nativeEvent, nativeEventTarget); rejectEvent.touchHistory = ResponderTouchHistoryStore_1.touchHistory; EventPropagators_1.accumulateDirectDispatches(rejectEvent); extracted = accumulate_1(extracted, rejectEvent); } } else { extracted = accumulate_1(extracted, grantEvent); changeResponder(wantsResponderInst, blockHostResponder); } return extracted; } /** * A transfer is a negotiation between a currently set responder and the next * element to claim responder status. Any start event could trigger a transfer * of responderInst. Any move event could trigger a transfer. * * @param {string} topLevelType Record from `BrowserEventConstants`. * @return {boolean} True if a transfer of responder could possibly occur. */ function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) { return topLevelInst && ( // responderIgnoreScroll: We are trying to migrate away from specifically // tracking native scroll events here and responderIgnoreScroll indicates we // will send topTouchCancel to handle canceling touch events instead topLevelType === 'topScroll' && !nativeEvent.responderIgnoreScroll || trackedTouchCount > 0 && topLevelType === 'topSelectionChange' || isStartish$1(topLevelType) || isMoveish$1(topLevelType)); } /** * Returns whether or not this touch end event makes it such that there are no * longer any touches that started inside of the current `responderInst`. * * @param {NativeEvent} nativeEvent Native touch end event. * @return {boolean} Whether or not this touch end event ends the responder. */ function noResponderTouches(nativeEvent) { var touches = nativeEvent.touches; if (!touches || touches.length === 0) { return true; } for (var i = 0; i < touches.length; i++) { var activeTouch = touches[i]; var target = activeTouch.target; if (target !== null && target !== undefined && target !== 0) { // Is the original touch location inside of the current responder? var targetInst = EventPluginUtils_1.getInstanceFromNode(target); if (ReactTreeTraversal.isAncestor(responderInst, targetInst)) { return false; } } } return true; } var ResponderEventPlugin = { /* For unit testing only */ _getResponder: function () { return responderInst; }, eventTypes: eventTypes, /** * We must be resilient to `targetInst` being `null` on `touchMove` or * `touchEnd`. On certain platforms, this means that a native scroll has * assumed control and the original touch targets are destroyed. */ extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { if (isStartish$1(topLevelType)) { trackedTouchCount += 1; } else if (isEndish$1(topLevelType)) { if (trackedTouchCount >= 0) { trackedTouchCount -= 1; } else { console.error('Ended a touch event which was not counted in `trackedTouchCount`.'); return null; } } ResponderTouchHistoryStore_1.recordTouchTrack(topLevelType, nativeEvent); var extracted = canTriggerTransfer(topLevelType, targetInst, nativeEvent) ? setResponderAndExtractTransfer(topLevelType, targetInst, nativeEvent, nativeEventTarget) : null; // Responder may or may not have transferred on a new touch start/move. // Regardless, whoever is the responder after any potential transfer, we // direct all touch start/move/ends to them in the form of // `onResponderMove/Start/End`. These will be called for *every* additional // finger that move/start/end, dispatched directly to whoever is the // current responder at that moment, until the responder is "released". // // These multiple individual change touch events are are always bookended // by `onResponderGrant`, and one of // (`onResponderRelease/onResponderTerminate`). var isResponderTouchStart = responderInst && isStartish$1(topLevelType); var isResponderTouchMove = responderInst && isMoveish$1(topLevelType); var isResponderTouchEnd = responderInst && isEndish$1(topLevelType); var incrementalTouch = isResponderTouchStart ? eventTypes.responderStart : isResponderTouchMove ? eventTypes.responderMove : isResponderTouchEnd ? eventTypes.responderEnd : null; if (incrementalTouch) { var gesture = ResponderSyntheticEvent_1.getPooled(incrementalTouch, responderInst, nativeEvent, nativeEventTarget); gesture.touchHistory = ResponderTouchHistoryStore_1.touchHistory; EventPropagators_1.accumulateDirectDispatches(gesture); extracted = accumulate_1(extracted, gesture); } var isResponderTerminate = responderInst && topLevelType === 'topTouchCancel'; var isResponderRelease = responderInst && !isResponderTerminate && isEndish$1(topLevelType) && noResponderTouches(nativeEvent); var finalTouch = isResponderTerminate ? eventTypes.responderTerminate : isResponderRelease ? eventTypes.responderRelease : null; if (finalTouch) { var finalEvent = ResponderSyntheticEvent_1.getPooled(finalTouch, responderInst, nativeEvent, nativeEventTarget); finalEvent.touchHistory = ResponderTouchHistoryStore_1.touchHistory; EventPropagators_1.accumulateDirectDispatches(finalEvent); extracted = accumulate_1(extracted, finalEvent); changeResponder(null); } var numberActiveTouches = ResponderTouchHistoryStore_1.touchHistory.numberActiveTouches; if (ResponderEventPlugin.GlobalInteractionHandler && numberActiveTouches !== previousActiveTouches) { ResponderEventPlugin.GlobalInteractionHandler.onChange(numberActiveTouches); } previousActiveTouches = numberActiveTouches; return extracted; }, GlobalResponderHandler: null, GlobalInteractionHandler: null, injection: { /** * @param {{onChange: (ReactID, ReactID) => void} GlobalResponderHandler * Object that handles any change in responder. Use this to inject * integration with an existing touch handling system etc. */ injectGlobalResponderHandler: function (GlobalResponderHandler) { ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; }, /** * @param {{onChange: (numberActiveTouches) => void} GlobalInteractionHandler * Object that handles any change in the number of active touches. */ injectGlobalInteractionHandler: function (GlobalInteractionHandler) { ResponderEventPlugin.GlobalInteractionHandler = GlobalInteractionHandler; } } }; var ResponderEventPlugin_1 = ResponderEventPlugin; /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @providesModule ReactDOMUnstableNativeDependenciesEntry */ var ReactDOMUnstableNativeDependencies = { injectComponentTree: EventPluginUtils_1.injection.injectComponentTree, ResponderEventPlugin: ResponderEventPlugin_1, ResponderTouchHistoryStore: ResponderTouchHistoryStore_1 }; // Inject react-dom's ComponentTree into this module. var ReactDOMComponentTree = reactDom.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactDOMComponentTree; ReactDOMUnstableNativeDependencies.injectComponentTree(ReactDOMComponentTree); var ReactDOMUnstableNativeDependenciesEntry = ReactDOMUnstableNativeDependencies; module.exports = ReactDOMUnstableNativeDependenciesEntry; })(); }