react-dom-unstable-native-dependencies.development.js 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629
  1. /** @license React v16.13.1
  2. * react-dom-unstable-native-dependencies.development.js
  3. *
  4. * Copyright (c) Facebook, Inc. and its affiliates.
  5. *
  6. * This source code is licensed under the MIT license found in the
  7. * LICENSE file in the root directory of this source tree.
  8. */
  9. 'use strict';
  10. if (process.env.NODE_ENV !== "production") {
  11. (function() {
  12. 'use strict';
  13. var ReactDOM = require('react-dom');
  14. var React = require('react');
  15. var _assign = require('object-assign');
  16. var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; // Prevent newer renderers from RTE when used with older react package versions.
  17. // Current owner and dispatcher used to share the same ref,
  18. // but PR #14548 split them out to better support the react-debug-tools package.
  19. if (!ReactSharedInternals.hasOwnProperty('ReactCurrentDispatcher')) {
  20. ReactSharedInternals.ReactCurrentDispatcher = {
  21. current: null
  22. };
  23. }
  24. if (!ReactSharedInternals.hasOwnProperty('ReactCurrentBatchConfig')) {
  25. ReactSharedInternals.ReactCurrentBatchConfig = {
  26. suspense: null
  27. };
  28. }
  29. // by calls to these methods by a Babel plugin.
  30. //
  31. // In PROD (or in packages without access to React internals),
  32. // they are left as they are instead.
  33. function warn(format) {
  34. {
  35. for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  36. args[_key - 1] = arguments[_key];
  37. }
  38. printWarning('warn', format, args);
  39. }
  40. }
  41. function error(format) {
  42. {
  43. for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
  44. args[_key2 - 1] = arguments[_key2];
  45. }
  46. printWarning('error', format, args);
  47. }
  48. }
  49. function printWarning(level, format, args) {
  50. // When changing this logic, you might want to also
  51. // update consoleWithStackDev.www.js as well.
  52. {
  53. var hasExistingStack = args.length > 0 && typeof args[args.length - 1] === 'string' && args[args.length - 1].indexOf('\n in') === 0;
  54. if (!hasExistingStack) {
  55. var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;
  56. var stack = ReactDebugCurrentFrame.getStackAddendum();
  57. if (stack !== '') {
  58. format += '%s';
  59. args = args.concat([stack]);
  60. }
  61. }
  62. var argsWithFormat = args.map(function (item) {
  63. return '' + item;
  64. }); // Careful: RN currently depends on this prefix
  65. argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it
  66. // breaks IE9: https://github.com/facebook/react/issues/13610
  67. // eslint-disable-next-line react-internal/no-production-logging
  68. Function.prototype.apply.call(console[level], console, argsWithFormat);
  69. try {
  70. // --- Welcome to debugging React ---
  71. // This error was thrown as a convenience so that you can use this stack
  72. // to find the callsite that caused this warning to fire.
  73. var argIndex = 0;
  74. var message = 'Warning: ' + format.replace(/%s/g, function () {
  75. return args[argIndex++];
  76. });
  77. throw new Error(message);
  78. } catch (x) {}
  79. }
  80. }
  81. {
  82. // In DEV mode, we swap out invokeGuardedCallback for a special version
  83. // that plays more nicely with the browser's DevTools. The idea is to preserve
  84. // "Pause on exceptions" behavior. Because React wraps all user-provided
  85. // functions in invokeGuardedCallback, and the production version of
  86. // invokeGuardedCallback uses a try-catch, all user exceptions are treated
  87. // like caught exceptions, and the DevTools won't pause unless the developer
  88. // takes the extra step of enabling pause on caught exceptions. This is
  89. // unintuitive, though, because even though React has caught the error, from
  90. // the developer's perspective, the error is uncaught.
  91. //
  92. // To preserve the expected "Pause on exceptions" behavior, we don't use a
  93. // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake
  94. // DOM node, and call the user-provided callback from inside an event handler
  95. // for that fake event. If the callback throws, the error is "captured" using
  96. // a global event handler. But because the error happens in a different
  97. // event loop context, it does not interrupt the normal program flow.
  98. // Effectively, this gives us try-catch behavior without actually using
  99. // try-catch. Neat!
  100. // Check that the browser supports the APIs we need to implement our special
  101. // DEV version of invokeGuardedCallback
  102. if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function' && typeof document !== 'undefined' && typeof document.createEvent === 'function') {
  103. var fakeNode = document.createElement('react');
  104. }
  105. }
  106. var getFiberCurrentPropsFromNode = null;
  107. var getInstanceFromNode = null;
  108. var getNodeFromInstance = null;
  109. function setComponentTree(getFiberCurrentPropsFromNodeImpl, getInstanceFromNodeImpl, getNodeFromInstanceImpl) {
  110. getFiberCurrentPropsFromNode = getFiberCurrentPropsFromNodeImpl;
  111. getInstanceFromNode = getInstanceFromNodeImpl;
  112. getNodeFromInstance = getNodeFromInstanceImpl;
  113. {
  114. if (!getNodeFromInstance || !getInstanceFromNode) {
  115. error('EventPluginUtils.setComponentTree(...): Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.');
  116. }
  117. }
  118. }
  119. var validateEventDispatches;
  120. {
  121. validateEventDispatches = function (event) {
  122. var dispatchListeners = event._dispatchListeners;
  123. var dispatchInstances = event._dispatchInstances;
  124. var listenersIsArr = Array.isArray(dispatchListeners);
  125. var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0;
  126. var instancesIsArr = Array.isArray(dispatchInstances);
  127. var instancesLen = instancesIsArr ? dispatchInstances.length : dispatchInstances ? 1 : 0;
  128. if (instancesIsArr !== listenersIsArr || instancesLen !== listenersLen) {
  129. error('EventPluginUtils: Invalid `event`.');
  130. }
  131. };
  132. }
  133. /**
  134. * Standard/simple iteration through an event's collected dispatches, but stops
  135. * at the first dispatch execution returning true, and returns that id.
  136. *
  137. * @return {?string} id of the first dispatch execution who's listener returns
  138. * true, or null if no listener returned true.
  139. */
  140. function executeDispatchesInOrderStopAtTrueImpl(event) {
  141. var dispatchListeners = event._dispatchListeners;
  142. var dispatchInstances = event._dispatchInstances;
  143. {
  144. validateEventDispatches(event);
  145. }
  146. if (Array.isArray(dispatchListeners)) {
  147. for (var i = 0; i < dispatchListeners.length; i++) {
  148. if (event.isPropagationStopped()) {
  149. break;
  150. } // Listeners and Instances are two parallel arrays that are always in sync.
  151. if (dispatchListeners[i](event, dispatchInstances[i])) {
  152. return dispatchInstances[i];
  153. }
  154. }
  155. } else if (dispatchListeners) {
  156. if (dispatchListeners(event, dispatchInstances)) {
  157. return dispatchInstances;
  158. }
  159. }
  160. return null;
  161. }
  162. /**
  163. * @see executeDispatchesInOrderStopAtTrueImpl
  164. */
  165. function executeDispatchesInOrderStopAtTrue(event) {
  166. var ret = executeDispatchesInOrderStopAtTrueImpl(event);
  167. event._dispatchInstances = null;
  168. event._dispatchListeners = null;
  169. return ret;
  170. }
  171. /**
  172. * Execution of a "direct" dispatch - there must be at most one dispatch
  173. * accumulated on the event or it is considered an error. It doesn't really make
  174. * sense for an event with multiple dispatches (bubbled) to keep track of the
  175. * return values at each dispatch execution, but it does tend to make sense when
  176. * dealing with "direct" dispatches.
  177. *
  178. * @return {*} The return value of executing the single dispatch.
  179. */
  180. function executeDirectDispatch(event) {
  181. {
  182. validateEventDispatches(event);
  183. }
  184. var dispatchListener = event._dispatchListeners;
  185. var dispatchInstance = event._dispatchInstances;
  186. if (!!Array.isArray(dispatchListener)) {
  187. {
  188. throw Error( "executeDirectDispatch(...): Invalid `event`." );
  189. }
  190. }
  191. event.currentTarget = dispatchListener ? getNodeFromInstance(dispatchInstance) : null;
  192. var res = dispatchListener ? dispatchListener(event) : null;
  193. event.currentTarget = null;
  194. event._dispatchListeners = null;
  195. event._dispatchInstances = null;
  196. return res;
  197. }
  198. /**
  199. * @param {SyntheticEvent} event
  200. * @return {boolean} True iff number of dispatches accumulated is greater than 0.
  201. */
  202. function hasDispatches(event) {
  203. return !!event._dispatchListeners;
  204. }
  205. var HostComponent = 5;
  206. function getParent(inst) {
  207. do {
  208. inst = inst.return; // TODO: If this is a HostRoot we might want to bail out.
  209. // That is depending on if we want nested subtrees (layers) to bubble
  210. // events to their parent. We could also go through parentNode on the
  211. // host node but that wouldn't work for React Native and doesn't let us
  212. // do the portal feature.
  213. } while (inst && inst.tag !== HostComponent);
  214. if (inst) {
  215. return inst;
  216. }
  217. return null;
  218. }
  219. /**
  220. * Return the lowest common ancestor of A and B, or null if they are in
  221. * different trees.
  222. */
  223. function getLowestCommonAncestor(instA, instB) {
  224. var depthA = 0;
  225. for (var tempA = instA; tempA; tempA = getParent(tempA)) {
  226. depthA++;
  227. }
  228. var depthB = 0;
  229. for (var tempB = instB; tempB; tempB = getParent(tempB)) {
  230. depthB++;
  231. } // If A is deeper, crawl up.
  232. while (depthA - depthB > 0) {
  233. instA = getParent(instA);
  234. depthA--;
  235. } // If B is deeper, crawl up.
  236. while (depthB - depthA > 0) {
  237. instB = getParent(instB);
  238. depthB--;
  239. } // Walk in lockstep until we find a match.
  240. var depth = depthA;
  241. while (depth--) {
  242. if (instA === instB || instA === instB.alternate) {
  243. return instA;
  244. }
  245. instA = getParent(instA);
  246. instB = getParent(instB);
  247. }
  248. return null;
  249. }
  250. /**
  251. * Return if A is an ancestor of B.
  252. */
  253. function isAncestor(instA, instB) {
  254. while (instB) {
  255. if (instA === instB || instA === instB.alternate) {
  256. return true;
  257. }
  258. instB = getParent(instB);
  259. }
  260. return false;
  261. }
  262. /**
  263. * Return the parent instance of the passed-in instance.
  264. */
  265. function getParentInstance(inst) {
  266. return getParent(inst);
  267. }
  268. /**
  269. * Simulates the traversal of a two-phase, capture/bubble event dispatch.
  270. */
  271. function traverseTwoPhase(inst, fn, arg) {
  272. var path = [];
  273. while (inst) {
  274. path.push(inst);
  275. inst = getParent(inst);
  276. }
  277. var i;
  278. for (i = path.length; i-- > 0;) {
  279. fn(path[i], 'captured', arg);
  280. }
  281. for (i = 0; i < path.length; i++) {
  282. fn(path[i], 'bubbled', arg);
  283. }
  284. }
  285. function isInteractive(tag) {
  286. return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea';
  287. }
  288. function shouldPreventMouseEvent(name, type, props) {
  289. switch (name) {
  290. case 'onClick':
  291. case 'onClickCapture':
  292. case 'onDoubleClick':
  293. case 'onDoubleClickCapture':
  294. case 'onMouseDown':
  295. case 'onMouseDownCapture':
  296. case 'onMouseMove':
  297. case 'onMouseMoveCapture':
  298. case 'onMouseUp':
  299. case 'onMouseUpCapture':
  300. case 'onMouseEnter':
  301. return !!(props.disabled && isInteractive(type));
  302. default:
  303. return false;
  304. }
  305. }
  306. /**
  307. * @param {object} inst The instance, which is the source of events.
  308. * @param {string} registrationName Name of listener (e.g. `onClick`).
  309. * @return {?function} The stored callback.
  310. */
  311. function getListener(inst, registrationName) {
  312. var listener; // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not
  313. // live here; needs to be moved to a better place soon
  314. var stateNode = inst.stateNode;
  315. if (!stateNode) {
  316. // Work in progress (ex: onload events in incremental mode).
  317. return null;
  318. }
  319. var props = getFiberCurrentPropsFromNode(stateNode);
  320. if (!props) {
  321. // Work in progress.
  322. return null;
  323. }
  324. listener = props[registrationName];
  325. if (shouldPreventMouseEvent(registrationName, inst.type, props)) {
  326. return null;
  327. }
  328. if (!(!listener || typeof listener === 'function')) {
  329. {
  330. throw Error( "Expected `" + registrationName + "` listener to be a function, instead got a value of `" + typeof listener + "` type." );
  331. }
  332. }
  333. return listener;
  334. }
  335. /**
  336. * Accumulates items that must not be null or undefined into the first one. This
  337. * is used to conserve memory by avoiding array allocations, and thus sacrifices
  338. * API cleanness. Since `current` can be null before being passed in and not
  339. * null after this function, make sure to assign it back to `current`:
  340. *
  341. * `a = accumulateInto(a, b);`
  342. *
  343. * This API should be sparingly used. Try `accumulate` for something cleaner.
  344. *
  345. * @return {*|array<*>} An accumulation of items.
  346. */
  347. function accumulateInto(current, next) {
  348. if (!(next != null)) {
  349. {
  350. throw Error( "accumulateInto(...): Accumulated items must not be null or undefined." );
  351. }
  352. }
  353. if (current == null) {
  354. return next;
  355. } // Both are not empty. Warning: Never call x.concat(y) when you are not
  356. // certain that x is an Array (x could be a string with concat method).
  357. if (Array.isArray(current)) {
  358. if (Array.isArray(next)) {
  359. current.push.apply(current, next);
  360. return current;
  361. }
  362. current.push(next);
  363. return current;
  364. }
  365. if (Array.isArray(next)) {
  366. // A bit too dangerous to mutate `next`.
  367. return [current].concat(next);
  368. }
  369. return [current, next];
  370. }
  371. /**
  372. * @param {array} arr an "accumulation" of items which is either an Array or
  373. * a single item. Useful when paired with the `accumulate` module. This is a
  374. * simple utility that allows us to reason about a collection of items, but
  375. * handling the case when there is exactly one item (and we do not need to
  376. * allocate an array).
  377. * @param {function} cb Callback invoked with each element or a collection.
  378. * @param {?} [scope] Scope used as `this` in a callback.
  379. */
  380. function forEachAccumulated(arr, cb, scope) {
  381. if (Array.isArray(arr)) {
  382. arr.forEach(cb, scope);
  383. } else if (arr) {
  384. cb.call(scope, arr);
  385. }
  386. }
  387. /**
  388. * Some event types have a notion of different registration names for different
  389. * "phases" of propagation. This finds listeners by a given phase.
  390. */
  391. function listenerAtPhase(inst, event, propagationPhase) {
  392. var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase];
  393. return getListener(inst, registrationName);
  394. }
  395. /**
  396. * A small set of propagation patterns, each of which will accept a small amount
  397. * of information, and generate a set of "dispatch ready event objects" - which
  398. * are sets of events that have already been annotated with a set of dispatched
  399. * listener functions/ids. The API is designed this way to discourage these
  400. * propagation strategies from actually executing the dispatches, since we
  401. * always want to collect the entire set of dispatches before executing even a
  402. * single one.
  403. */
  404. /**
  405. * Tags a `SyntheticEvent` with dispatched listeners. Creating this function
  406. * here, allows us to not have to bind or create functions for each event.
  407. * Mutating the event's members allows us to not have to create a wrapping
  408. * "dispatch" object that pairs the event with the listener.
  409. */
  410. function accumulateDirectionalDispatches(inst, phase, event) {
  411. {
  412. if (!inst) {
  413. error('Dispatching inst must not be null');
  414. }
  415. }
  416. var listener = listenerAtPhase(inst, event, phase);
  417. if (listener) {
  418. event._dispatchListeners = accumulateInto(event._dispatchListeners, listener);
  419. event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
  420. }
  421. }
  422. /**
  423. * Collect dispatches (must be entirely collected before dispatching - see unit
  424. * tests). Lazily allocate the array to conserve memory. We must loop through
  425. * each event and perform the traversal for each one. We cannot perform a
  426. * single traversal for the entire collection of events because each event may
  427. * have a different target.
  428. */
  429. function accumulateTwoPhaseDispatchesSingle(event) {
  430. if (event && event.dispatchConfig.phasedRegistrationNames) {
  431. traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event);
  432. }
  433. }
  434. /**
  435. * Same as `accumulateTwoPhaseDispatchesSingle`, but skips over the targetID.
  436. */
  437. function accumulateTwoPhaseDispatchesSingleSkipTarget(event) {
  438. if (event && event.dispatchConfig.phasedRegistrationNames) {
  439. var targetInst = event._targetInst;
  440. var parentInst = targetInst ? getParentInstance(targetInst) : null;
  441. traverseTwoPhase(parentInst, accumulateDirectionalDispatches, event);
  442. }
  443. }
  444. /**
  445. * Accumulates without regard to direction, does not look for phased
  446. * registration names. Same as `accumulateDirectDispatchesSingle` but without
  447. * requiring that the `dispatchMarker` be the same as the dispatched ID.
  448. */
  449. function accumulateDispatches(inst, ignoredDirection, event) {
  450. if (inst && event && event.dispatchConfig.registrationName) {
  451. var registrationName = event.dispatchConfig.registrationName;
  452. var listener = getListener(inst, registrationName);
  453. if (listener) {
  454. event._dispatchListeners = accumulateInto(event._dispatchListeners, listener);
  455. event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
  456. }
  457. }
  458. }
  459. /**
  460. * Accumulates dispatches on an `SyntheticEvent`, but only for the
  461. * `dispatchMarker`.
  462. * @param {SyntheticEvent} event
  463. */
  464. function accumulateDirectDispatchesSingle(event) {
  465. if (event && event.dispatchConfig.registrationName) {
  466. accumulateDispatches(event._targetInst, null, event);
  467. }
  468. }
  469. function accumulateTwoPhaseDispatches(events) {
  470. forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
  471. }
  472. function accumulateTwoPhaseDispatchesSkipTarget(events) {
  473. forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget);
  474. }
  475. function accumulateDirectDispatches(events) {
  476. forEachAccumulated(events, accumulateDirectDispatchesSingle);
  477. }
  478. var EVENT_POOL_SIZE = 10;
  479. /**
  480. * @interface Event
  481. * @see http://www.w3.org/TR/DOM-Level-3-Events/
  482. */
  483. var EventInterface = {
  484. type: null,
  485. target: null,
  486. // currentTarget is set when dispatching; no use in copying it here
  487. currentTarget: function () {
  488. return null;
  489. },
  490. eventPhase: null,
  491. bubbles: null,
  492. cancelable: null,
  493. timeStamp: function (event) {
  494. return event.timeStamp || Date.now();
  495. },
  496. defaultPrevented: null,
  497. isTrusted: null
  498. };
  499. function functionThatReturnsTrue() {
  500. return true;
  501. }
  502. function functionThatReturnsFalse() {
  503. return false;
  504. }
  505. /**
  506. * Synthetic events are dispatched by event plugins, typically in response to a
  507. * top-level event delegation handler.
  508. *
  509. * These systems should generally use pooling to reduce the frequency of garbage
  510. * collection. The system should check `isPersistent` to determine whether the
  511. * event should be released into the pool after being dispatched. Users that
  512. * need a persisted event should invoke `persist`.
  513. *
  514. * Synthetic events (and subclasses) implement the DOM Level 3 Events API by
  515. * normalizing browser quirks. Subclasses do not necessarily have to implement a
  516. * DOM interface; custom application-specific events can also subclass this.
  517. *
  518. * @param {object} dispatchConfig Configuration used to dispatch this event.
  519. * @param {*} targetInst Marker identifying the event target.
  520. * @param {object} nativeEvent Native browser event.
  521. * @param {DOMEventTarget} nativeEventTarget Target node.
  522. */
  523. function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) {
  524. {
  525. // these have a getter/setter for warnings
  526. delete this.nativeEvent;
  527. delete this.preventDefault;
  528. delete this.stopPropagation;
  529. delete this.isDefaultPrevented;
  530. delete this.isPropagationStopped;
  531. }
  532. this.dispatchConfig = dispatchConfig;
  533. this._targetInst = targetInst;
  534. this.nativeEvent = nativeEvent;
  535. var Interface = this.constructor.Interface;
  536. for (var propName in Interface) {
  537. if (!Interface.hasOwnProperty(propName)) {
  538. continue;
  539. }
  540. {
  541. delete this[propName]; // this has a getter/setter for warnings
  542. }
  543. var normalize = Interface[propName];
  544. if (normalize) {
  545. this[propName] = normalize(nativeEvent);
  546. } else {
  547. if (propName === 'target') {
  548. this.target = nativeEventTarget;
  549. } else {
  550. this[propName] = nativeEvent[propName];
  551. }
  552. }
  553. }
  554. var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false;
  555. if (defaultPrevented) {
  556. this.isDefaultPrevented = functionThatReturnsTrue;
  557. } else {
  558. this.isDefaultPrevented = functionThatReturnsFalse;
  559. }
  560. this.isPropagationStopped = functionThatReturnsFalse;
  561. return this;
  562. }
  563. _assign(SyntheticEvent.prototype, {
  564. preventDefault: function () {
  565. this.defaultPrevented = true;
  566. var event = this.nativeEvent;
  567. if (!event) {
  568. return;
  569. }
  570. if (event.preventDefault) {
  571. event.preventDefault();
  572. } else if (typeof event.returnValue !== 'unknown') {
  573. event.returnValue = false;
  574. }
  575. this.isDefaultPrevented = functionThatReturnsTrue;
  576. },
  577. stopPropagation: function () {
  578. var event = this.nativeEvent;
  579. if (!event) {
  580. return;
  581. }
  582. if (event.stopPropagation) {
  583. event.stopPropagation();
  584. } else if (typeof event.cancelBubble !== 'unknown') {
  585. // The ChangeEventPlugin registers a "propertychange" event for
  586. // IE. This event does not support bubbling or cancelling, and
  587. // any references to cancelBubble throw "Member not found". A
  588. // typeof check of "unknown" circumvents this issue (and is also
  589. // IE specific).
  590. event.cancelBubble = true;
  591. }
  592. this.isPropagationStopped = functionThatReturnsTrue;
  593. },
  594. /**
  595. * We release all dispatched `SyntheticEvent`s after each event loop, adding
  596. * them back into the pool. This allows a way to hold onto a reference that
  597. * won't be added back into the pool.
  598. */
  599. persist: function () {
  600. this.isPersistent = functionThatReturnsTrue;
  601. },
  602. /**
  603. * Checks if this event should be released back into the pool.
  604. *
  605. * @return {boolean} True if this should not be released, false otherwise.
  606. */
  607. isPersistent: functionThatReturnsFalse,
  608. /**
  609. * `PooledClass` looks for `destructor` on each instance it releases.
  610. */
  611. destructor: function () {
  612. var Interface = this.constructor.Interface;
  613. for (var propName in Interface) {
  614. {
  615. Object.defineProperty(this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName]));
  616. }
  617. }
  618. this.dispatchConfig = null;
  619. this._targetInst = null;
  620. this.nativeEvent = null;
  621. this.isDefaultPrevented = functionThatReturnsFalse;
  622. this.isPropagationStopped = functionThatReturnsFalse;
  623. this._dispatchListeners = null;
  624. this._dispatchInstances = null;
  625. {
  626. Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null));
  627. Object.defineProperty(this, 'isDefaultPrevented', getPooledWarningPropertyDefinition('isDefaultPrevented', functionThatReturnsFalse));
  628. Object.defineProperty(this, 'isPropagationStopped', getPooledWarningPropertyDefinition('isPropagationStopped', functionThatReturnsFalse));
  629. Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', function () {}));
  630. Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', function () {}));
  631. }
  632. }
  633. });
  634. SyntheticEvent.Interface = EventInterface;
  635. /**
  636. * Helper to reduce boilerplate when creating subclasses.
  637. */
  638. SyntheticEvent.extend = function (Interface) {
  639. var Super = this;
  640. var E = function () {};
  641. E.prototype = Super.prototype;
  642. var prototype = new E();
  643. function Class() {
  644. return Super.apply(this, arguments);
  645. }
  646. _assign(prototype, Class.prototype);
  647. Class.prototype = prototype;
  648. Class.prototype.constructor = Class;
  649. Class.Interface = _assign({}, Super.Interface, Interface);
  650. Class.extend = Super.extend;
  651. addEventPoolingTo(Class);
  652. return Class;
  653. };
  654. addEventPoolingTo(SyntheticEvent);
  655. /**
  656. * Helper to nullify syntheticEvent instance properties when destructing
  657. *
  658. * @param {String} propName
  659. * @param {?object} getVal
  660. * @return {object} defineProperty object
  661. */
  662. function getPooledWarningPropertyDefinition(propName, getVal) {
  663. var isFunction = typeof getVal === 'function';
  664. return {
  665. configurable: true,
  666. set: set,
  667. get: get
  668. };
  669. function set(val) {
  670. var action = isFunction ? 'setting the method' : 'setting the property';
  671. warn(action, 'This is effectively a no-op');
  672. return val;
  673. }
  674. function get() {
  675. var action = isFunction ? 'accessing the method' : 'accessing the property';
  676. var result = isFunction ? 'This is a no-op function' : 'This is set to null';
  677. warn(action, result);
  678. return getVal;
  679. }
  680. function warn(action, result) {
  681. {
  682. error("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);
  683. }
  684. }
  685. }
  686. function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) {
  687. var EventConstructor = this;
  688. if (EventConstructor.eventPool.length) {
  689. var instance = EventConstructor.eventPool.pop();
  690. EventConstructor.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst);
  691. return instance;
  692. }
  693. return new EventConstructor(dispatchConfig, targetInst, nativeEvent, nativeInst);
  694. }
  695. function releasePooledEvent(event) {
  696. var EventConstructor = this;
  697. if (!(event instanceof EventConstructor)) {
  698. {
  699. throw Error( "Trying to release an event instance into a pool of a different type." );
  700. }
  701. }
  702. event.destructor();
  703. if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) {
  704. EventConstructor.eventPool.push(event);
  705. }
  706. }
  707. function addEventPoolingTo(EventConstructor) {
  708. EventConstructor.eventPool = [];
  709. EventConstructor.getPooled = getPooledEvent;
  710. EventConstructor.release = releasePooledEvent;
  711. }
  712. /**
  713. * `touchHistory` isn't actually on the native event, but putting it in the
  714. * interface will ensure that it is cleaned up when pooled/destroyed. The
  715. * `ResponderEventPlugin` will populate it appropriately.
  716. */
  717. var ResponderSyntheticEvent = SyntheticEvent.extend({
  718. touchHistory: function (nativeEvent) {
  719. return null; // Actually doesn't even look at the native event.
  720. }
  721. });
  722. // Note: ideally these would be imported from DOMTopLevelEventTypes,
  723. // but our build system currently doesn't let us do that from a fork.
  724. var TOP_TOUCH_START = 'touchstart';
  725. var TOP_TOUCH_MOVE = 'touchmove';
  726. var TOP_TOUCH_END = 'touchend';
  727. var TOP_TOUCH_CANCEL = 'touchcancel';
  728. var TOP_SCROLL = 'scroll';
  729. var TOP_SELECTION_CHANGE = 'selectionchange';
  730. var TOP_MOUSE_DOWN = 'mousedown';
  731. var TOP_MOUSE_MOVE = 'mousemove';
  732. var TOP_MOUSE_UP = 'mouseup';
  733. function isStartish(topLevelType) {
  734. return topLevelType === TOP_TOUCH_START || topLevelType === TOP_MOUSE_DOWN;
  735. }
  736. function isMoveish(topLevelType) {
  737. return topLevelType === TOP_TOUCH_MOVE || topLevelType === TOP_MOUSE_MOVE;
  738. }
  739. function isEndish(topLevelType) {
  740. return topLevelType === TOP_TOUCH_END || topLevelType === TOP_TOUCH_CANCEL || topLevelType === TOP_MOUSE_UP;
  741. }
  742. var startDependencies = [TOP_TOUCH_START, TOP_MOUSE_DOWN];
  743. var moveDependencies = [TOP_TOUCH_MOVE, TOP_MOUSE_MOVE];
  744. var endDependencies = [TOP_TOUCH_CANCEL, TOP_TOUCH_END, TOP_MOUSE_UP];
  745. /**
  746. * Tracks the position and time of each active touch by `touch.identifier`. We
  747. * should typically only see IDs in the range of 1-20 because IDs get recycled
  748. * when touches end and start again.
  749. */
  750. var MAX_TOUCH_BANK = 20;
  751. var touchBank = [];
  752. var touchHistory = {
  753. touchBank: touchBank,
  754. numberActiveTouches: 0,
  755. // If there is only one active touch, we remember its location. This prevents
  756. // us having to loop through all of the touches all the time in the most
  757. // common case.
  758. indexOfSingleActiveTouch: -1,
  759. mostRecentTimeStamp: 0
  760. };
  761. function timestampForTouch(touch) {
  762. // The legacy internal implementation provides "timeStamp", which has been
  763. // renamed to "timestamp". Let both work for now while we iron it out
  764. // TODO (evv): rename timeStamp to timestamp in internal code
  765. return touch.timeStamp || touch.timestamp;
  766. }
  767. /**
  768. * TODO: Instead of making gestures recompute filtered velocity, we could
  769. * include a built in velocity computation that can be reused globally.
  770. */
  771. function createTouchRecord(touch) {
  772. return {
  773. touchActive: true,
  774. startPageX: touch.pageX,
  775. startPageY: touch.pageY,
  776. startTimeStamp: timestampForTouch(touch),
  777. currentPageX: touch.pageX,
  778. currentPageY: touch.pageY,
  779. currentTimeStamp: timestampForTouch(touch),
  780. previousPageX: touch.pageX,
  781. previousPageY: touch.pageY,
  782. previousTimeStamp: timestampForTouch(touch)
  783. };
  784. }
  785. function resetTouchRecord(touchRecord, touch) {
  786. touchRecord.touchActive = true;
  787. touchRecord.startPageX = touch.pageX;
  788. touchRecord.startPageY = touch.pageY;
  789. touchRecord.startTimeStamp = timestampForTouch(touch);
  790. touchRecord.currentPageX = touch.pageX;
  791. touchRecord.currentPageY = touch.pageY;
  792. touchRecord.currentTimeStamp = timestampForTouch(touch);
  793. touchRecord.previousPageX = touch.pageX;
  794. touchRecord.previousPageY = touch.pageY;
  795. touchRecord.previousTimeStamp = timestampForTouch(touch);
  796. }
  797. function getTouchIdentifier(_ref) {
  798. var identifier = _ref.identifier;
  799. if (!(identifier != null)) {
  800. {
  801. throw Error( "Touch object is missing identifier." );
  802. }
  803. }
  804. {
  805. if (identifier > MAX_TOUCH_BANK) {
  806. error('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);
  807. }
  808. }
  809. return identifier;
  810. }
  811. function recordTouchStart(touch) {
  812. var identifier = getTouchIdentifier(touch);
  813. var touchRecord = touchBank[identifier];
  814. if (touchRecord) {
  815. resetTouchRecord(touchRecord, touch);
  816. } else {
  817. touchBank[identifier] = createTouchRecord(touch);
  818. }
  819. touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
  820. }
  821. function recordTouchMove(touch) {
  822. var touchRecord = touchBank[getTouchIdentifier(touch)];
  823. if (touchRecord) {
  824. touchRecord.touchActive = true;
  825. touchRecord.previousPageX = touchRecord.currentPageX;
  826. touchRecord.previousPageY = touchRecord.currentPageY;
  827. touchRecord.previousTimeStamp = touchRecord.currentTimeStamp;
  828. touchRecord.currentPageX = touch.pageX;
  829. touchRecord.currentPageY = touch.pageY;
  830. touchRecord.currentTimeStamp = timestampForTouch(touch);
  831. touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
  832. } else {
  833. {
  834. warn('Cannot record touch move without a touch start.\n' + 'Touch Move: %s\n' + 'Touch Bank: %s', printTouch(touch), printTouchBank());
  835. }
  836. }
  837. }
  838. function recordTouchEnd(touch) {
  839. var touchRecord = touchBank[getTouchIdentifier(touch)];
  840. if (touchRecord) {
  841. touchRecord.touchActive = false;
  842. touchRecord.previousPageX = touchRecord.currentPageX;
  843. touchRecord.previousPageY = touchRecord.currentPageY;
  844. touchRecord.previousTimeStamp = touchRecord.currentTimeStamp;
  845. touchRecord.currentPageX = touch.pageX;
  846. touchRecord.currentPageY = touch.pageY;
  847. touchRecord.currentTimeStamp = timestampForTouch(touch);
  848. touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
  849. } else {
  850. {
  851. warn('Cannot record touch end without a touch start.\n' + 'Touch End: %s\n' + 'Touch Bank: %s', printTouch(touch), printTouchBank());
  852. }
  853. }
  854. }
  855. function printTouch(touch) {
  856. return JSON.stringify({
  857. identifier: touch.identifier,
  858. pageX: touch.pageX,
  859. pageY: touch.pageY,
  860. timestamp: timestampForTouch(touch)
  861. });
  862. }
  863. function printTouchBank() {
  864. var printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK));
  865. if (touchBank.length > MAX_TOUCH_BANK) {
  866. printed += ' (original size: ' + touchBank.length + ')';
  867. }
  868. return printed;
  869. }
  870. var ResponderTouchHistoryStore = {
  871. recordTouchTrack: function (topLevelType, nativeEvent) {
  872. if (isMoveish(topLevelType)) {
  873. nativeEvent.changedTouches.forEach(recordTouchMove);
  874. } else if (isStartish(topLevelType)) {
  875. nativeEvent.changedTouches.forEach(recordTouchStart);
  876. touchHistory.numberActiveTouches = nativeEvent.touches.length;
  877. if (touchHistory.numberActiveTouches === 1) {
  878. touchHistory.indexOfSingleActiveTouch = nativeEvent.touches[0].identifier;
  879. }
  880. } else if (isEndish(topLevelType)) {
  881. nativeEvent.changedTouches.forEach(recordTouchEnd);
  882. touchHistory.numberActiveTouches = nativeEvent.touches.length;
  883. if (touchHistory.numberActiveTouches === 1) {
  884. for (var i = 0; i < touchBank.length; i++) {
  885. var touchTrackToCheck = touchBank[i];
  886. if (touchTrackToCheck != null && touchTrackToCheck.touchActive) {
  887. touchHistory.indexOfSingleActiveTouch = i;
  888. break;
  889. }
  890. }
  891. {
  892. var activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch];
  893. if (activeRecord == null || !activeRecord.touchActive) {
  894. error('Cannot find single active touch.');
  895. }
  896. }
  897. }
  898. }
  899. },
  900. touchHistory: touchHistory
  901. };
  902. /**
  903. * Accumulates items that must not be null or undefined.
  904. *
  905. * This is used to conserve memory by avoiding array allocations.
  906. *
  907. * @return {*|array<*>} An accumulation of items.
  908. */
  909. function accumulate(current, next) {
  910. if (!(next != null)) {
  911. {
  912. throw Error( "accumulate(...): Accumulated items must not be null or undefined." );
  913. }
  914. }
  915. if (current == null) {
  916. return next;
  917. } // Both are not empty. Warning: Never call x.concat(y) when you are not
  918. // certain that x is an Array (x could be a string with concat method).
  919. if (Array.isArray(current)) {
  920. return current.concat(next);
  921. }
  922. if (Array.isArray(next)) {
  923. return [current].concat(next);
  924. }
  925. return [current, next];
  926. }
  927. /**
  928. * Instance of element that should respond to touch/move types of interactions,
  929. * as indicated explicitly by relevant callbacks.
  930. */
  931. var responderInst = null;
  932. /**
  933. * Count of current touches. A textInput should become responder iff the
  934. * selection changes while there is a touch on the screen.
  935. */
  936. var trackedTouchCount = 0;
  937. var changeResponder = function (nextResponderInst, blockHostResponder) {
  938. var oldResponderInst = responderInst;
  939. responderInst = nextResponderInst;
  940. if (ResponderEventPlugin.GlobalResponderHandler !== null) {
  941. ResponderEventPlugin.GlobalResponderHandler.onChange(oldResponderInst, nextResponderInst, blockHostResponder);
  942. }
  943. };
  944. var eventTypes = {
  945. /**
  946. * On a `touchStart`/`mouseDown`, is it desired that this element become the
  947. * responder?
  948. */
  949. startShouldSetResponder: {
  950. phasedRegistrationNames: {
  951. bubbled: 'onStartShouldSetResponder',
  952. captured: 'onStartShouldSetResponderCapture'
  953. },
  954. dependencies: startDependencies
  955. },
  956. /**
  957. * On a `scroll`, is it desired that this element become the responder? This
  958. * is usually not needed, but should be used to retroactively infer that a
  959. * `touchStart` had occurred during momentum scroll. During a momentum scroll,
  960. * a touch start will be immediately followed by a scroll event if the view is
  961. * currently scrolling.
  962. *
  963. * TODO: This shouldn't bubble.
  964. */
  965. scrollShouldSetResponder: {
  966. phasedRegistrationNames: {
  967. bubbled: 'onScrollShouldSetResponder',
  968. captured: 'onScrollShouldSetResponderCapture'
  969. },
  970. dependencies: [TOP_SCROLL]
  971. },
  972. /**
  973. * On text selection change, should this element become the responder? This
  974. * is needed for text inputs or other views with native selection, so the
  975. * JS view can claim the responder.
  976. *
  977. * TODO: This shouldn't bubble.
  978. */
  979. selectionChangeShouldSetResponder: {
  980. phasedRegistrationNames: {
  981. bubbled: 'onSelectionChangeShouldSetResponder',
  982. captured: 'onSelectionChangeShouldSetResponderCapture'
  983. },
  984. dependencies: [TOP_SELECTION_CHANGE]
  985. },
  986. /**
  987. * On a `touchMove`/`mouseMove`, is it desired that this element become the
  988. * responder?
  989. */
  990. moveShouldSetResponder: {
  991. phasedRegistrationNames: {
  992. bubbled: 'onMoveShouldSetResponder',
  993. captured: 'onMoveShouldSetResponderCapture'
  994. },
  995. dependencies: moveDependencies
  996. },
  997. /**
  998. * Direct responder events dispatched directly to responder. Do not bubble.
  999. */
  1000. responderStart: {
  1001. registrationName: 'onResponderStart',
  1002. dependencies: startDependencies
  1003. },
  1004. responderMove: {
  1005. registrationName: 'onResponderMove',
  1006. dependencies: moveDependencies
  1007. },
  1008. responderEnd: {
  1009. registrationName: 'onResponderEnd',
  1010. dependencies: endDependencies
  1011. },
  1012. responderRelease: {
  1013. registrationName: 'onResponderRelease',
  1014. dependencies: endDependencies
  1015. },
  1016. responderTerminationRequest: {
  1017. registrationName: 'onResponderTerminationRequest',
  1018. dependencies: []
  1019. },
  1020. responderGrant: {
  1021. registrationName: 'onResponderGrant',
  1022. dependencies: []
  1023. },
  1024. responderReject: {
  1025. registrationName: 'onResponderReject',
  1026. dependencies: []
  1027. },
  1028. responderTerminate: {
  1029. registrationName: 'onResponderTerminate',
  1030. dependencies: []
  1031. }
  1032. };
  1033. /**
  1034. *
  1035. * Responder System:
  1036. * ----------------
  1037. *
  1038. * - A global, solitary "interaction lock" on a view.
  1039. * - If a node becomes the responder, it should convey visual feedback
  1040. * immediately to indicate so, either by highlighting or moving accordingly.
  1041. * - To be the responder means, that touches are exclusively important to that
  1042. * responder view, and no other view.
  1043. * - While touches are still occurring, the responder lock can be transferred to
  1044. * a new view, but only to increasingly "higher" views (meaning ancestors of
  1045. * the current responder).
  1046. *
  1047. * Responder being granted:
  1048. * ------------------------
  1049. *
  1050. * - Touch starts, moves, and scrolls can cause an ID to become the responder.
  1051. * - We capture/bubble `startShouldSetResponder`/`moveShouldSetResponder` to
  1052. * the "appropriate place".
  1053. * - If nothing is currently the responder, the "appropriate place" is the
  1054. * initiating event's `targetID`.
  1055. * - If something *is* already the responder, the "appropriate place" is the
  1056. * first common ancestor of the event target and the current `responderInst`.
  1057. * - Some negotiation happens: See the timing diagram below.
  1058. * - Scrolled views automatically become responder. The reasoning is that a
  1059. * platform scroll view that isn't built on top of the responder system has
  1060. * began scrolling, and the active responder must now be notified that the
  1061. * interaction is no longer locked to it - the system has taken over.
  1062. *
  1063. * - Responder being released:
  1064. * As soon as no more touches that *started* inside of descendants of the
  1065. * *current* responderInst, an `onResponderRelease` event is dispatched to the
  1066. * current responder, and the responder lock is released.
  1067. *
  1068. * TODO:
  1069. * - on "end", a callback hook for `onResponderEndShouldRemainResponder` that
  1070. * determines if the responder lock should remain.
  1071. * - If a view shouldn't "remain" the responder, any active touches should by
  1072. * default be considered "dead" and do not influence future negotiations or
  1073. * bubble paths. It should be as if those touches do not exist.
  1074. * -- For multitouch: Usually a translate-z will choose to "remain" responder
  1075. * after one out of many touches ended. For translate-y, usually the view
  1076. * doesn't wish to "remain" responder after one of many touches end.
  1077. * - Consider building this on top of a `stopPropagation` model similar to
  1078. * `W3C` events.
  1079. * - Ensure that `onResponderTerminate` is called on touch cancels, whether or
  1080. * not `onResponderTerminationRequest` returns `true` or `false`.
  1081. *
  1082. */
  1083. /* Negotiation Performed
  1084. +-----------------------+
  1085. / \
  1086. Process low level events to + Current Responder + wantsResponderID
  1087. determine who to perform negot-| (if any exists at all) |
  1088. iation/transition | Otherwise just pass through|
  1089. -------------------------------+----------------------------+------------------+
  1090. Bubble to find first ID | |
  1091. to return true:wantsResponderID| |
  1092. | |
  1093. +-------------+ | |
  1094. | onTouchStart| | |
  1095. +------+------+ none | |
  1096. | return| |
  1097. +-----------v-------------+true| +------------------------+ |
  1098. |onStartShouldSetResponder|----->|onResponderStart (cur) |<-----------+
  1099. +-----------+-------------+ | +------------------------+ | |
  1100. | | | +--------+-------+
  1101. | returned true for| false:REJECT +-------->|onResponderReject
  1102. | wantsResponderID | | | +----------------+
  1103. | (now attempt | +------------------+-----+ |
  1104. | handoff) | | onResponder | |
  1105. +------------------->| TerminationRequest| |
  1106. | +------------------+-----+ |
  1107. | | | +----------------+
  1108. | true:GRANT +-------->|onResponderGrant|
  1109. | | +--------+-------+
  1110. | +------------------------+ | |
  1111. | | onResponderTerminate |<-----------+
  1112. | +------------------+-----+ |
  1113. | | | +----------------+
  1114. | +-------->|onResponderStart|
  1115. | | +----------------+
  1116. Bubble to find first ID | |
  1117. to return true:wantsResponderID| |
  1118. | |
  1119. +-------------+ | |
  1120. | onTouchMove | | |
  1121. +------+------+ none | |
  1122. | return| |
  1123. +-----------v-------------+true| +------------------------+ |
  1124. |onMoveShouldSetResponder |----->|onResponderMove (cur) |<-----------+
  1125. +-----------+-------------+ | +------------------------+ | |
  1126. | | | +--------+-------+
  1127. | returned true for| false:REJECT +-------->|onResponderRejec|
  1128. | wantsResponderID | | | +----------------+
  1129. | (now attempt | +------------------+-----+ |
  1130. | handoff) | | onResponder | |
  1131. +------------------->| TerminationRequest| |
  1132. | +------------------+-----+ |
  1133. | | | +----------------+
  1134. | true:GRANT +-------->|onResponderGrant|
  1135. | | +--------+-------+
  1136. | +------------------------+ | |
  1137. | | onResponderTerminate |<-----------+
  1138. | +------------------+-----+ |
  1139. | | | +----------------+
  1140. | +-------->|onResponderMove |
  1141. | | +----------------+
  1142. | |
  1143. | |
  1144. Some active touch started| |
  1145. inside current responder | +------------------------+ |
  1146. +------------------------->| onResponderEnd | |
  1147. | | +------------------------+ |
  1148. +---+---------+ | |
  1149. | onTouchEnd | | |
  1150. +---+---------+ | |
  1151. | | +------------------------+ |
  1152. +------------------------->| onResponderEnd | |
  1153. No active touches started| +-----------+------------+ |
  1154. inside current responder | | |
  1155. | v |
  1156. | +------------------------+ |
  1157. | | onResponderRelease | |
  1158. | +------------------------+ |
  1159. | |
  1160. + + */
  1161. /**
  1162. * A note about event ordering in the `EventPluginRegistry`.
  1163. *
  1164. * Suppose plugins are injected in the following order:
  1165. *
  1166. * `[R, S, C]`
  1167. *
  1168. * To help illustrate the example, assume `S` is `SimpleEventPlugin` (for
  1169. * `onClick` etc) and `R` is `ResponderEventPlugin`.
  1170. *
  1171. * "Deferred-Dispatched Events":
  1172. *
  1173. * - The current event plugin system will traverse the list of injected plugins,
  1174. * in order, and extract events by collecting the plugin's return value of
  1175. * `extractEvents()`.
  1176. * - These events that are returned from `extractEvents` are "deferred
  1177. * dispatched events".
  1178. * - When returned from `extractEvents`, deferred-dispatched events contain an
  1179. * "accumulation" of deferred dispatches.
  1180. * - These deferred dispatches are accumulated/collected before they are
  1181. * returned, but processed at a later time by the `EventPluginRegistry` (hence the
  1182. * name deferred).
  1183. *
  1184. * In the process of returning their deferred-dispatched events, event plugins
  1185. * themselves can dispatch events on-demand without returning them from
  1186. * `extractEvents`. Plugins might want to do this, so that they can use event
  1187. * dispatching as a tool that helps them decide which events should be extracted
  1188. * in the first place.
  1189. *
  1190. * "On-Demand-Dispatched Events":
  1191. *
  1192. * - On-demand-dispatched events are not returned from `extractEvents`.
  1193. * - On-demand-dispatched events are dispatched during the process of returning
  1194. * the deferred-dispatched events.
  1195. * - They should not have side effects.
  1196. * - They should be avoided, and/or eventually be replaced with another
  1197. * abstraction that allows event plugins to perform multiple "rounds" of event
  1198. * extraction.
  1199. *
  1200. * Therefore, the sequence of event dispatches becomes:
  1201. *
  1202. * - `R`s on-demand events (if any) (dispatched by `R` on-demand)
  1203. * - `S`s on-demand events (if any) (dispatched by `S` on-demand)
  1204. * - `C`s on-demand events (if any) (dispatched by `C` on-demand)
  1205. * - `R`s extracted events (if any) (dispatched by `EventPluginRegistry`)
  1206. * - `S`s extracted events (if any) (dispatched by `EventPluginRegistry`)
  1207. * - `C`s extracted events (if any) (dispatched by `EventPluginRegistry`)
  1208. *
  1209. * In the case of `ResponderEventPlugin`: If the `startShouldSetResponder`
  1210. * on-demand dispatch returns `true` (and some other details are satisfied) the
  1211. * `onResponderGrant` deferred dispatched event is returned from
  1212. * `extractEvents`. The sequence of dispatch executions in this case
  1213. * will appear as follows:
  1214. *
  1215. * - `startShouldSetResponder` (`ResponderEventPlugin` dispatches on-demand)
  1216. * - `touchStartCapture` (`EventPluginRegistry` dispatches as usual)
  1217. * - `touchStart` (`EventPluginRegistry` dispatches as usual)
  1218. * - `responderGrant/Reject` (`EventPluginRegistry` dispatches as usual)
  1219. */
  1220. function setResponderAndExtractTransfer(topLevelType, targetInst, nativeEvent, nativeEventTarget) {
  1221. var shouldSetEventType = isStartish(topLevelType) ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) ? eventTypes.moveShouldSetResponder : topLevelType === TOP_SELECTION_CHANGE ? eventTypes.selectionChangeShouldSetResponder : eventTypes.scrollShouldSetResponder; // TODO: stop one short of the current responder.
  1222. var bubbleShouldSetFrom = !responderInst ? targetInst : getLowestCommonAncestor(responderInst, targetInst); // When capturing/bubbling the "shouldSet" event, we want to skip the target
  1223. // (deepest ID) if it happens to be the current responder. The reasoning:
  1224. // It's strange to get an `onMoveShouldSetResponder` when you're *already*
  1225. // the responder.
  1226. var skipOverBubbleShouldSetFrom = bubbleShouldSetFrom === responderInst;
  1227. var shouldSetEvent = ResponderSyntheticEvent.getPooled(shouldSetEventType, bubbleShouldSetFrom, nativeEvent, nativeEventTarget);
  1228. shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
  1229. if (skipOverBubbleShouldSetFrom) {
  1230. accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent);
  1231. } else {
  1232. accumulateTwoPhaseDispatches(shouldSetEvent);
  1233. }
  1234. var wantsResponderInst = executeDispatchesInOrderStopAtTrue(shouldSetEvent);
  1235. if (!shouldSetEvent.isPersistent()) {
  1236. shouldSetEvent.constructor.release(shouldSetEvent);
  1237. }
  1238. if (!wantsResponderInst || wantsResponderInst === responderInst) {
  1239. return null;
  1240. }
  1241. var extracted;
  1242. var grantEvent = ResponderSyntheticEvent.getPooled(eventTypes.responderGrant, wantsResponderInst, nativeEvent, nativeEventTarget);
  1243. grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
  1244. accumulateDirectDispatches(grantEvent);
  1245. var blockHostResponder = executeDirectDispatch(grantEvent) === true;
  1246. if (responderInst) {
  1247. var terminationRequestEvent = ResponderSyntheticEvent.getPooled(eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget);
  1248. terminationRequestEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
  1249. accumulateDirectDispatches(terminationRequestEvent);
  1250. var shouldSwitch = !hasDispatches(terminationRequestEvent) || executeDirectDispatch(terminationRequestEvent);
  1251. if (!terminationRequestEvent.isPersistent()) {
  1252. terminationRequestEvent.constructor.release(terminationRequestEvent);
  1253. }
  1254. if (shouldSwitch) {
  1255. var terminateEvent = ResponderSyntheticEvent.getPooled(eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget);
  1256. terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
  1257. accumulateDirectDispatches(terminateEvent);
  1258. extracted = accumulate(extracted, [grantEvent, terminateEvent]);
  1259. changeResponder(wantsResponderInst, blockHostResponder);
  1260. } else {
  1261. var rejectEvent = ResponderSyntheticEvent.getPooled(eventTypes.responderReject, wantsResponderInst, nativeEvent, nativeEventTarget);
  1262. rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
  1263. accumulateDirectDispatches(rejectEvent);
  1264. extracted = accumulate(extracted, rejectEvent);
  1265. }
  1266. } else {
  1267. extracted = accumulate(extracted, grantEvent);
  1268. changeResponder(wantsResponderInst, blockHostResponder);
  1269. }
  1270. return extracted;
  1271. }
  1272. /**
  1273. * A transfer is a negotiation between a currently set responder and the next
  1274. * element to claim responder status. Any start event could trigger a transfer
  1275. * of responderInst. Any move event could trigger a transfer.
  1276. *
  1277. * @param {string} topLevelType Record from `BrowserEventConstants`.
  1278. * @return {boolean} True if a transfer of responder could possibly occur.
  1279. */
  1280. function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) {
  1281. return topLevelInst && ( // responderIgnoreScroll: We are trying to migrate away from specifically
  1282. // tracking native scroll events here and responderIgnoreScroll indicates we
  1283. // will send topTouchCancel to handle canceling touch events instead
  1284. topLevelType === TOP_SCROLL && !nativeEvent.responderIgnoreScroll || trackedTouchCount > 0 && topLevelType === TOP_SELECTION_CHANGE || isStartish(topLevelType) || isMoveish(topLevelType));
  1285. }
  1286. /**
  1287. * Returns whether or not this touch end event makes it such that there are no
  1288. * longer any touches that started inside of the current `responderInst`.
  1289. *
  1290. * @param {NativeEvent} nativeEvent Native touch end event.
  1291. * @return {boolean} Whether or not this touch end event ends the responder.
  1292. */
  1293. function noResponderTouches(nativeEvent) {
  1294. var touches = nativeEvent.touches;
  1295. if (!touches || touches.length === 0) {
  1296. return true;
  1297. }
  1298. for (var i = 0; i < touches.length; i++) {
  1299. var activeTouch = touches[i];
  1300. var target = activeTouch.target;
  1301. if (target !== null && target !== undefined && target !== 0) {
  1302. // Is the original touch location inside of the current responder?
  1303. var targetInst = getInstanceFromNode(target);
  1304. if (isAncestor(responderInst, targetInst)) {
  1305. return false;
  1306. }
  1307. }
  1308. }
  1309. return true;
  1310. }
  1311. var ResponderEventPlugin = {
  1312. /* For unit testing only */
  1313. _getResponder: function () {
  1314. return responderInst;
  1315. },
  1316. eventTypes: eventTypes,
  1317. /**
  1318. * We must be resilient to `targetInst` being `null` on `touchMove` or
  1319. * `touchEnd`. On certain platforms, this means that a native scroll has
  1320. * assumed control and the original touch targets are destroyed.
  1321. */
  1322. extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags) {
  1323. if (isStartish(topLevelType)) {
  1324. trackedTouchCount += 1;
  1325. } else if (isEndish(topLevelType)) {
  1326. if (trackedTouchCount >= 0) {
  1327. trackedTouchCount -= 1;
  1328. } else {
  1329. {
  1330. warn('Ended a touch event which was not counted in `trackedTouchCount`.');
  1331. }
  1332. return null;
  1333. }
  1334. }
  1335. ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent);
  1336. 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.
  1337. // Regardless, whoever is the responder after any potential transfer, we
  1338. // direct all touch start/move/ends to them in the form of
  1339. // `onResponderMove/Start/End`. These will be called for *every* additional
  1340. // finger that move/start/end, dispatched directly to whoever is the
  1341. // current responder at that moment, until the responder is "released".
  1342. //
  1343. // These multiple individual change touch events are are always bookended
  1344. // by `onResponderGrant`, and one of
  1345. // (`onResponderRelease/onResponderTerminate`).
  1346. var isResponderTouchStart = responderInst && isStartish(topLevelType);
  1347. var isResponderTouchMove = responderInst && isMoveish(topLevelType);
  1348. var isResponderTouchEnd = responderInst && isEndish(topLevelType);
  1349. var incrementalTouch = isResponderTouchStart ? eventTypes.responderStart : isResponderTouchMove ? eventTypes.responderMove : isResponderTouchEnd ? eventTypes.responderEnd : null;
  1350. if (incrementalTouch) {
  1351. var gesture = ResponderSyntheticEvent.getPooled(incrementalTouch, responderInst, nativeEvent, nativeEventTarget);
  1352. gesture.touchHistory = ResponderTouchHistoryStore.touchHistory;
  1353. accumulateDirectDispatches(gesture);
  1354. extracted = accumulate(extracted, gesture);
  1355. }
  1356. var isResponderTerminate = responderInst && topLevelType === TOP_TOUCH_CANCEL;
  1357. var isResponderRelease = responderInst && !isResponderTerminate && isEndish(topLevelType) && noResponderTouches(nativeEvent);
  1358. var finalTouch = isResponderTerminate ? eventTypes.responderTerminate : isResponderRelease ? eventTypes.responderRelease : null;
  1359. if (finalTouch) {
  1360. var finalEvent = ResponderSyntheticEvent.getPooled(finalTouch, responderInst, nativeEvent, nativeEventTarget);
  1361. finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
  1362. accumulateDirectDispatches(finalEvent);
  1363. extracted = accumulate(extracted, finalEvent);
  1364. changeResponder(null);
  1365. }
  1366. return extracted;
  1367. },
  1368. GlobalResponderHandler: null,
  1369. injection: {
  1370. /**
  1371. * @param {{onChange: (ReactID, ReactID) => void} GlobalResponderHandler
  1372. * Object that handles any change in responder. Use this to inject
  1373. * integration with an existing touch handling system etc.
  1374. */
  1375. injectGlobalResponderHandler: function (GlobalResponderHandler) {
  1376. ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler;
  1377. }
  1378. }
  1379. };
  1380. // Keep in sync with ReactDOM.js, ReactTestUtils.js, and ReactTestUtilsAct.js:
  1381. var _ReactDOM$__SECRET_IN = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Events,
  1382. getInstanceFromNode$1 = _ReactDOM$__SECRET_IN[0],
  1383. getNodeFromInstance$1 = _ReactDOM$__SECRET_IN[1],
  1384. getFiberCurrentPropsFromNode$1 = _ReactDOM$__SECRET_IN[2],
  1385. injectEventPluginsByName = _ReactDOM$__SECRET_IN[3];
  1386. setComponentTree(getFiberCurrentPropsFromNode$1, getInstanceFromNode$1, getNodeFromInstance$1);
  1387. var ReactDOMUnstableNativeDependencies = /*#__PURE__*/Object.freeze({
  1388. __proto__: null,
  1389. ResponderEventPlugin: ResponderEventPlugin,
  1390. ResponderTouchHistoryStore: ResponderTouchHistoryStore,
  1391. injectEventPluginsByName: injectEventPluginsByName
  1392. });
  1393. var unstableNativeDependencies = ReactDOMUnstableNativeDependencies;
  1394. module.exports = unstableNativeDependencies;
  1395. })();
  1396. }