yeet
This commit is contained in:
76
node_modules/react-native/Libraries/Interaction/Batchinator.js
generated
vendored
Normal file
76
node_modules/react-native/Libraries/Interaction/Batchinator.js
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const InteractionManager = require('./InteractionManager');
|
||||
|
||||
/**
|
||||
* A simple class for batching up invocations of a low-pri callback. A timeout is set to run the
|
||||
* callback once after a delay, no matter how many times it's scheduled. Once the delay is reached,
|
||||
* InteractionManager.runAfterInteractions is used to invoke the callback after any hi-pri
|
||||
* interactions are done running.
|
||||
*
|
||||
* Make sure to cleanup with dispose(). Example:
|
||||
*
|
||||
* class Widget extends React.Component {
|
||||
* _batchedSave: new Batchinator(() => this._saveState, 1000);
|
||||
* _saveSate() {
|
||||
* // save this.state to disk
|
||||
* }
|
||||
* componentDidUpdate() {
|
||||
* this._batchedSave.schedule();
|
||||
* }
|
||||
* componentWillUnmount() {
|
||||
* this._batchedSave.dispose();
|
||||
* }
|
||||
* ...
|
||||
* }
|
||||
*/
|
||||
class Batchinator {
|
||||
_callback: () => void;
|
||||
_delay: number;
|
||||
_taskHandle: ?{cancel: () => void, ...};
|
||||
constructor(callback: () => void, delayMS: number) {
|
||||
this._delay = delayMS;
|
||||
this._callback = callback;
|
||||
}
|
||||
/*
|
||||
* Cleanup any pending tasks.
|
||||
*
|
||||
* By default, if there is a pending task the callback is run immediately. Set the option abort to
|
||||
* true to not call the callback if it was pending.
|
||||
*/
|
||||
dispose(options: {abort: boolean, ...} = {abort: false}) {
|
||||
if (this._taskHandle) {
|
||||
this._taskHandle.cancel();
|
||||
if (!options.abort) {
|
||||
this._callback();
|
||||
}
|
||||
this._taskHandle = null;
|
||||
}
|
||||
}
|
||||
schedule() {
|
||||
if (this._taskHandle) {
|
||||
return;
|
||||
}
|
||||
const timeoutHandle = setTimeout(() => {
|
||||
this._taskHandle = InteractionManager.runAfterInteractions(() => {
|
||||
// Note that we clear the handle before invoking the callback so that if the callback calls
|
||||
// schedule again, it will actually schedule another task.
|
||||
this._taskHandle = null;
|
||||
this._callback();
|
||||
});
|
||||
}, this._delay);
|
||||
this._taskHandle = {cancel: () => clearTimeout(timeoutHandle)};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Batchinator;
|
62
node_modules/react-native/Libraries/Interaction/BridgeSpyStallHandler.js
generated
vendored
Normal file
62
node_modules/react-native/Libraries/Interaction/BridgeSpyStallHandler.js
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const JSEventLoopWatchdog = require('./JSEventLoopWatchdog');
|
||||
const MessageQueue = require('../BatchedBridge/MessageQueue');
|
||||
|
||||
const infoLog = require('../Utilities/infoLog');
|
||||
|
||||
const BridgeSpyStallHandler = {
|
||||
register: function() {
|
||||
let spyBuffer = [];
|
||||
MessageQueue.spy(data => {
|
||||
spyBuffer.push(data);
|
||||
});
|
||||
const TO_JS = 0;
|
||||
JSEventLoopWatchdog.addHandler({
|
||||
onStall: () => {
|
||||
infoLog(
|
||||
spyBuffer.length + ' bridge messages during stall: ',
|
||||
spyBuffer.map(info => {
|
||||
let args = '<args>';
|
||||
try {
|
||||
args = JSON.stringify(info.args);
|
||||
} catch (e1) {
|
||||
if (Array.isArray(info.args)) {
|
||||
args = info.args.map(arg => {
|
||||
try {
|
||||
return JSON.stringify(arg);
|
||||
} catch (e2) {
|
||||
return '?';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
args = 'keys:' + JSON.stringify(Object.keys(info.args));
|
||||
}
|
||||
}
|
||||
return (
|
||||
`${info.type === TO_JS ? 'N->JS' : 'JS->N'} : ` +
|
||||
`${info.module ? info.module + '.' : ''}${
|
||||
info.method
|
||||
}(${JSON.stringify(args)})`
|
||||
);
|
||||
}),
|
||||
);
|
||||
},
|
||||
onIterate: () => {
|
||||
spyBuffer = [];
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = BridgeSpyStallHandler;
|
84
node_modules/react-native/Libraries/Interaction/FrameRateLogger.js
generated
vendored
Normal file
84
node_modules/react-native/Libraries/Interaction/FrameRateLogger.js
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import NativeFrameRateLogger from './NativeFrameRateLogger';
|
||||
|
||||
const invariant = require('invariant');
|
||||
|
||||
/**
|
||||
* Flow API for native FrameRateLogger module. If the native module is not installed, function calls
|
||||
* are just no-ops.
|
||||
*
|
||||
* Typical behavior is that `setContext` is called when a new screen is loaded (e.g. via a
|
||||
* navigation integration), and then `beginScroll` is called by `ScrollResponder` at which point the
|
||||
* native module then begins tracking frame drops. When `ScrollResponder` calls `endScroll`, the
|
||||
* native module gathers up all it's frame drop data and reports it via an analytics pipeline for
|
||||
* analysis.
|
||||
*
|
||||
* Note that `beginScroll` may be called multiple times by `ScrollResponder` - unclear if that's a
|
||||
* bug, but the native module should be robust to that.
|
||||
*
|
||||
* In the future we may add support for tracking frame drops in other types of interactions beyond
|
||||
* scrolling.
|
||||
*/
|
||||
const FrameRateLogger = {
|
||||
/**
|
||||
* Enable `debug` to see local logs of what's going on. `reportStackTraces` will grab stack traces
|
||||
* during UI thread stalls and upload them if the native module supports it.
|
||||
*/
|
||||
setGlobalOptions: function(options: {
|
||||
debug?: boolean,
|
||||
reportStackTraces?: boolean,
|
||||
...
|
||||
}) {
|
||||
if (options.debug !== undefined) {
|
||||
invariant(
|
||||
NativeFrameRateLogger,
|
||||
'Trying to debug FrameRateLogger without the native module!',
|
||||
);
|
||||
}
|
||||
if (NativeFrameRateLogger) {
|
||||
// Needs to clone the object first to avoid modifying the argument.
|
||||
const optionsClone = {
|
||||
debug: !!options.debug,
|
||||
reportStackTraces: !!options.reportStackTraces,
|
||||
};
|
||||
NativeFrameRateLogger.setGlobalOptions(optionsClone);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Must call `setContext` before any events can be properly tracked, which is done automatically
|
||||
* in `AppRegistry`, but navigation is also a common place to hook in.
|
||||
*/
|
||||
setContext: function(context: string) {
|
||||
NativeFrameRateLogger && NativeFrameRateLogger.setContext(context);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called in `ScrollResponder` so any component that uses that module will handle this
|
||||
* automatically.
|
||||
*/
|
||||
beginScroll() {
|
||||
NativeFrameRateLogger && NativeFrameRateLogger.beginScroll();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called in `ScrollResponder` so any component that uses that module will handle this
|
||||
* automatically.
|
||||
*/
|
||||
endScroll() {
|
||||
NativeFrameRateLogger && NativeFrameRateLogger.endScroll();
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = FrameRateLogger;
|
222
node_modules/react-native/Libraries/Interaction/InteractionManager.js
generated
vendored
Normal file
222
node_modules/react-native/Libraries/Interaction/InteractionManager.js
generated
vendored
Normal file
@ -0,0 +1,222 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const BatchedBridge = require('../BatchedBridge/BatchedBridge');
|
||||
const EventEmitter = require('../vendor/emitter/EventEmitter');
|
||||
const TaskQueue = require('./TaskQueue');
|
||||
|
||||
const infoLog = require('../Utilities/infoLog');
|
||||
const invariant = require('invariant');
|
||||
const keyMirror = require('fbjs/lib/keyMirror');
|
||||
|
||||
export type Handle = number;
|
||||
import type {Task} from './TaskQueue';
|
||||
|
||||
const _emitter = new EventEmitter();
|
||||
|
||||
const DEBUG_DELAY: 0 = 0;
|
||||
const DEBUG: false = false;
|
||||
|
||||
/**
|
||||
* InteractionManager allows long-running work to be scheduled after any
|
||||
* interactions/animations have completed. In particular, this allows JavaScript
|
||||
* animations to run smoothly.
|
||||
*
|
||||
* Applications can schedule tasks to run after interactions with the following:
|
||||
*
|
||||
* ```
|
||||
* InteractionManager.runAfterInteractions(() => {
|
||||
* // ...long-running synchronous task...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Compare this to other scheduling alternatives:
|
||||
*
|
||||
* - requestAnimationFrame(): for code that animates a view over time.
|
||||
* - setImmediate/setTimeout(): run code later, note this may delay animations.
|
||||
* - runAfterInteractions(): run code later, without delaying active animations.
|
||||
*
|
||||
* The touch handling system considers one or more active touches to be an
|
||||
* 'interaction' and will delay `runAfterInteractions()` callbacks until all
|
||||
* touches have ended or been cancelled.
|
||||
*
|
||||
* InteractionManager also allows applications to register animations by
|
||||
* creating an interaction 'handle' on animation start, and clearing it upon
|
||||
* completion:
|
||||
*
|
||||
* ```
|
||||
* var handle = InteractionManager.createInteractionHandle();
|
||||
* // run animation... (`runAfterInteractions` tasks are queued)
|
||||
* // later, on animation completion:
|
||||
* InteractionManager.clearInteractionHandle(handle);
|
||||
* // queued tasks run if all handles were cleared
|
||||
* ```
|
||||
*
|
||||
* `runAfterInteractions` takes either a plain callback function, or a
|
||||
* `PromiseTask` object with a `gen` method that returns a `Promise`. If a
|
||||
* `PromiseTask` is supplied, then it is fully resolved (including asynchronous
|
||||
* dependencies that also schedule more tasks via `runAfterInteractions`) before
|
||||
* starting on the next task that might have been queued up synchronously
|
||||
* earlier.
|
||||
*
|
||||
* By default, queued tasks are executed together in a loop in one
|
||||
* `setImmediate` batch. If `setDeadline` is called with a positive number, then
|
||||
* tasks will only be executed until the deadline (in terms of js event loop run
|
||||
* time) approaches, at which point execution will yield via setTimeout,
|
||||
* allowing events such as touches to start interactions and block queued tasks
|
||||
* from executing, making apps more responsive.
|
||||
*/
|
||||
const InteractionManager = {
|
||||
Events: keyMirror({
|
||||
interactionStart: true,
|
||||
interactionComplete: true,
|
||||
}),
|
||||
|
||||
/**
|
||||
* Schedule a function to run after all interactions have completed. Returns a cancellable
|
||||
* "promise".
|
||||
*/
|
||||
runAfterInteractions(
|
||||
task: ?Task,
|
||||
): {
|
||||
then: Function,
|
||||
done: Function,
|
||||
cancel: Function,
|
||||
...
|
||||
} {
|
||||
const tasks = [];
|
||||
const promise = new Promise(resolve => {
|
||||
_scheduleUpdate();
|
||||
if (task) {
|
||||
tasks.push(task);
|
||||
}
|
||||
tasks.push({
|
||||
run: resolve,
|
||||
name: 'resolve ' + ((task && task.name) || '?'),
|
||||
});
|
||||
_taskQueue.enqueueTasks(tasks);
|
||||
});
|
||||
return {
|
||||
then: promise.then.bind(promise),
|
||||
done: (...args) => {
|
||||
if (promise.done) {
|
||||
return promise.done(...args);
|
||||
} else {
|
||||
console.warn(
|
||||
'Tried to call done when not supported by current Promise implementation.',
|
||||
);
|
||||
}
|
||||
},
|
||||
cancel: function() {
|
||||
_taskQueue.cancelTasks(tasks);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify manager that an interaction has started.
|
||||
*/
|
||||
createInteractionHandle(): Handle {
|
||||
DEBUG && infoLog('InteractionManager: create interaction handle');
|
||||
_scheduleUpdate();
|
||||
const handle = ++_inc;
|
||||
_addInteractionSet.add(handle);
|
||||
return handle;
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify manager that an interaction has completed.
|
||||
*/
|
||||
clearInteractionHandle(handle: Handle) {
|
||||
DEBUG && infoLog('InteractionManager: clear interaction handle');
|
||||
invariant(!!handle, 'InteractionManager: Must provide a handle to clear.');
|
||||
_scheduleUpdate();
|
||||
_addInteractionSet.delete(handle);
|
||||
_deleteInteractionSet.add(handle);
|
||||
},
|
||||
|
||||
addListener: (_emitter.addListener.bind(_emitter): $FlowFixMe),
|
||||
|
||||
/**
|
||||
* A positive number will use setTimeout to schedule any tasks after the
|
||||
* eventLoopRunningTime hits the deadline value, otherwise all tasks will be
|
||||
* executed in one setImmediate batch (default).
|
||||
*/
|
||||
setDeadline(deadline: number) {
|
||||
_deadline = deadline;
|
||||
},
|
||||
};
|
||||
|
||||
const _interactionSet = new Set();
|
||||
const _addInteractionSet = new Set();
|
||||
const _deleteInteractionSet = new Set();
|
||||
const _taskQueue = new TaskQueue({onMoreTasks: _scheduleUpdate});
|
||||
let _nextUpdateHandle = 0;
|
||||
let _inc = 0;
|
||||
let _deadline = -1;
|
||||
|
||||
declare function setImmediate(callback: any, ...args: Array<any>): number;
|
||||
|
||||
/**
|
||||
* Schedule an asynchronous update to the interaction state.
|
||||
*/
|
||||
function _scheduleUpdate() {
|
||||
if (!_nextUpdateHandle) {
|
||||
if (_deadline > 0) {
|
||||
/* $FlowFixMe(>=0.63.0 site=react_native_fb) This comment suppresses an
|
||||
* error found when Flow v0.63 was deployed. To see the error delete this
|
||||
* comment and run Flow. */
|
||||
_nextUpdateHandle = setTimeout(_processUpdate, 0 + DEBUG_DELAY);
|
||||
} else {
|
||||
_nextUpdateHandle = setImmediate(_processUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify listeners, process queue, etc
|
||||
*/
|
||||
function _processUpdate() {
|
||||
_nextUpdateHandle = 0;
|
||||
|
||||
const interactionCount = _interactionSet.size;
|
||||
_addInteractionSet.forEach(handle => _interactionSet.add(handle));
|
||||
_deleteInteractionSet.forEach(handle => _interactionSet.delete(handle));
|
||||
const nextInteractionCount = _interactionSet.size;
|
||||
|
||||
if (interactionCount !== 0 && nextInteractionCount === 0) {
|
||||
// transition from 1+ --> 0 interactions
|
||||
_emitter.emit(InteractionManager.Events.interactionComplete);
|
||||
} else if (interactionCount === 0 && nextInteractionCount !== 0) {
|
||||
// transition from 0 --> 1+ interactions
|
||||
_emitter.emit(InteractionManager.Events.interactionStart);
|
||||
}
|
||||
|
||||
// process the queue regardless of a transition
|
||||
if (nextInteractionCount === 0) {
|
||||
while (_taskQueue.hasTasksToProcess()) {
|
||||
_taskQueue.processNext();
|
||||
if (
|
||||
_deadline > 0 &&
|
||||
BatchedBridge.getEventLoopRunningTime() >= _deadline
|
||||
) {
|
||||
// Hit deadline before processing all tasks, so process more later.
|
||||
_scheduleUpdate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_addInteractionSet.clear();
|
||||
_deleteInteractionSet.clear();
|
||||
}
|
||||
|
||||
module.exports = InteractionManager;
|
55
node_modules/react-native/Libraries/Interaction/InteractionMixin.js
generated
vendored
Normal file
55
node_modules/react-native/Libraries/Interaction/InteractionMixin.js
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const InteractionManager = require('./InteractionManager');
|
||||
import {type Handle} from './InteractionManager';
|
||||
|
||||
/**
|
||||
* This mixin provides safe versions of InteractionManager start/end methods
|
||||
* that ensures `clearInteractionHandle` is always called
|
||||
* once per start, even if the component is unmounted.
|
||||
*/
|
||||
const InteractionMixin = {
|
||||
componentWillUnmount: function() {
|
||||
while (this._interactionMixinHandles.length) {
|
||||
InteractionManager.clearInteractionHandle(
|
||||
this._interactionMixinHandles.pop(),
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
_interactionMixinHandles: ([]: Array<number>),
|
||||
|
||||
createInteractionHandle: function(): Handle {
|
||||
const handle = InteractionManager.createInteractionHandle();
|
||||
this._interactionMixinHandles.push(handle);
|
||||
return handle;
|
||||
},
|
||||
|
||||
clearInteractionHandle: function(clearHandle: number): void {
|
||||
InteractionManager.clearInteractionHandle(clearHandle);
|
||||
this._interactionMixinHandles = this._interactionMixinHandles.filter(
|
||||
handle => handle !== clearHandle,
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Schedule work for after all interactions have completed.
|
||||
*
|
||||
* @param {function} callback
|
||||
*/
|
||||
runAfterInteractions: function(callback: Function): void {
|
||||
InteractionManager.runAfterInteractions(callback);
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = InteractionMixin;
|
23
node_modules/react-native/Libraries/Interaction/InteractionStallDebugger.js
generated
vendored
Normal file
23
node_modules/react-native/Libraries/Interaction/InteractionStallDebugger.js
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const BridgeSpyStallHandler = require('./BridgeSpyStallHandler');
|
||||
const JSEventLoopWatchdog = require('./JSEventLoopWatchdog');
|
||||
|
||||
const InteractionStallDebugger = {
|
||||
install(options: {thresholdMS: number, ...}): void {
|
||||
JSEventLoopWatchdog.install(options);
|
||||
BridgeSpyStallHandler.register();
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = InteractionStallDebugger;
|
93
node_modules/react-native/Libraries/Interaction/JSEventLoopWatchdog.js
generated
vendored
Normal file
93
node_modules/react-native/Libraries/Interaction/JSEventLoopWatchdog.js
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const infoLog = require('../Utilities/infoLog');
|
||||
const performanceNow = require('fbjs/lib/performanceNow');
|
||||
|
||||
type Handler = {
|
||||
onIterate?: () => void,
|
||||
onStall: (params: {
|
||||
lastInterval: number,
|
||||
busyTime: number,
|
||||
...
|
||||
}) => ?string,
|
||||
...
|
||||
};
|
||||
|
||||
/**
|
||||
* A utility for tracking stalls in the JS event loop that prevent timers and
|
||||
* other events from being processed in a timely manner.
|
||||
*
|
||||
* The "stall" time is defined as the amount of time in access of the acceptable
|
||||
* threshold, which is typically around 100-200ms. So if the treshold is set to
|
||||
* 100 and a timer fires 150 ms later than it was scheduled because the event
|
||||
* loop was tied up, that would be considered a 50ms stall.
|
||||
*
|
||||
* By default, logs stall events to the console when installed. Can also be
|
||||
* queried with `getStats`.
|
||||
*/
|
||||
const JSEventLoopWatchdog = {
|
||||
getStats: function(): Object {
|
||||
return {stallCount, totalStallTime, longestStall, acceptableBusyTime};
|
||||
},
|
||||
reset: function() {
|
||||
infoLog('JSEventLoopWatchdog: reset');
|
||||
totalStallTime = 0;
|
||||
stallCount = 0;
|
||||
longestStall = 0;
|
||||
lastInterval = performanceNow();
|
||||
},
|
||||
addHandler: function(handler: Handler) {
|
||||
handlers.push(handler);
|
||||
},
|
||||
install: function({thresholdMS}: {thresholdMS: number, ...}) {
|
||||
acceptableBusyTime = thresholdMS;
|
||||
if (installed) {
|
||||
return;
|
||||
}
|
||||
installed = true;
|
||||
lastInterval = performanceNow();
|
||||
function iteration() {
|
||||
const now = performanceNow();
|
||||
const busyTime = now - lastInterval;
|
||||
if (busyTime >= thresholdMS) {
|
||||
const stallTime = busyTime - thresholdMS;
|
||||
stallCount++;
|
||||
totalStallTime += stallTime;
|
||||
longestStall = Math.max(longestStall, stallTime);
|
||||
let msg =
|
||||
`JSEventLoopWatchdog: JS thread busy for ${busyTime}ms. ` +
|
||||
`${totalStallTime}ms in ${stallCount} stalls so far. `;
|
||||
handlers.forEach(handler => {
|
||||
msg += handler.onStall({lastInterval, busyTime}) || '';
|
||||
});
|
||||
infoLog(msg);
|
||||
}
|
||||
handlers.forEach(handler => {
|
||||
handler.onIterate && handler.onIterate();
|
||||
});
|
||||
lastInterval = now;
|
||||
setTimeout(iteration, thresholdMS / 5);
|
||||
}
|
||||
iteration();
|
||||
},
|
||||
};
|
||||
|
||||
let acceptableBusyTime = 0;
|
||||
let installed = false;
|
||||
let totalStallTime = 0;
|
||||
let stallCount = 0;
|
||||
let longestStall = 0;
|
||||
let lastInterval = 0;
|
||||
const handlers: Array<Handler> = [];
|
||||
|
||||
module.exports = JSEventLoopWatchdog;
|
24
node_modules/react-native/Libraries/Interaction/NativeFrameRateLogger.js
generated
vendored
Normal file
24
node_modules/react-native/Libraries/Interaction/NativeFrameRateLogger.js
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
import type {TurboModule} from '../TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+setGlobalOptions: (options: {|
|
||||
+debug?: ?boolean,
|
||||
+reportStackTraces?: ?boolean,
|
||||
|}) => void;
|
||||
+setContext: (context: string) => void;
|
||||
+beginScroll: () => void;
|
||||
+endScroll: () => void;
|
||||
}
|
||||
|
||||
export default (TurboModuleRegistry.get<Spec>('FrameRateLogger'): ?Spec);
|
581
node_modules/react-native/Libraries/Interaction/PanResponder.js
generated
vendored
Normal file
581
node_modules/react-native/Libraries/Interaction/PanResponder.js
generated
vendored
Normal file
@ -0,0 +1,581 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const InteractionManager = require('./InteractionManager');
|
||||
const TouchHistoryMath = require('./TouchHistoryMath');
|
||||
|
||||
import type {PressEvent} from '../Types/CoreEventTypes';
|
||||
|
||||
const currentCentroidXOfTouchesChangedAfter =
|
||||
TouchHistoryMath.currentCentroidXOfTouchesChangedAfter;
|
||||
const currentCentroidYOfTouchesChangedAfter =
|
||||
TouchHistoryMath.currentCentroidYOfTouchesChangedAfter;
|
||||
const previousCentroidXOfTouchesChangedAfter =
|
||||
TouchHistoryMath.previousCentroidXOfTouchesChangedAfter;
|
||||
const previousCentroidYOfTouchesChangedAfter =
|
||||
TouchHistoryMath.previousCentroidYOfTouchesChangedAfter;
|
||||
const currentCentroidX = TouchHistoryMath.currentCentroidX;
|
||||
const currentCentroidY = TouchHistoryMath.currentCentroidY;
|
||||
|
||||
/**
|
||||
* `PanResponder` reconciles several touches into a single gesture. It makes
|
||||
* single-touch gestures resilient to extra touches, and can be used to
|
||||
* recognize simple multi-touch gestures.
|
||||
*
|
||||
* By default, `PanResponder` holds an `InteractionManager` handle to block
|
||||
* long-running JS events from interrupting active gestures.
|
||||
*
|
||||
* It provides a predictable wrapper of the responder handlers provided by the
|
||||
* [gesture responder system](docs/gesture-responder-system.html).
|
||||
* For each handler, it provides a new `gestureState` object alongside the
|
||||
* native event object:
|
||||
*
|
||||
* ```
|
||||
* onPanResponderMove: (event, gestureState) => {}
|
||||
* ```
|
||||
*
|
||||
* A native event is a synthetic touch event with the following form:
|
||||
*
|
||||
* - `nativeEvent`
|
||||
* + `changedTouches` - Array of all touch events that have changed since the last event
|
||||
* + `identifier` - The ID of the touch
|
||||
* + `locationX` - The X position of the touch, relative to the element
|
||||
* + `locationY` - The Y position of the touch, relative to the element
|
||||
* + `pageX` - The X position of the touch, relative to the root element
|
||||
* + `pageY` - The Y position of the touch, relative to the root element
|
||||
* + `target` - The node id of the element receiving the touch event
|
||||
* + `timestamp` - A time identifier for the touch, useful for velocity calculation
|
||||
* + `touches` - Array of all current touches on the screen
|
||||
*
|
||||
* A `gestureState` object has the following:
|
||||
*
|
||||
* - `stateID` - ID of the gestureState- persisted as long as there at least
|
||||
* one touch on screen
|
||||
* - `moveX` - the latest screen coordinates of the recently-moved touch
|
||||
* - `moveY` - the latest screen coordinates of the recently-moved touch
|
||||
* - `x0` - the screen coordinates of the responder grant
|
||||
* - `y0` - the screen coordinates of the responder grant
|
||||
* - `dx` - accumulated distance of the gesture since the touch started
|
||||
* - `dy` - accumulated distance of the gesture since the touch started
|
||||
* - `vx` - current velocity of the gesture
|
||||
* - `vy` - current velocity of the gesture
|
||||
* - `numberActiveTouches` - Number of touches currently on screen
|
||||
*
|
||||
* ### Basic Usage
|
||||
*
|
||||
* ```
|
||||
* componentWillMount: function() {
|
||||
* this._panResponder = PanResponder.create({
|
||||
* // Ask to be the responder:
|
||||
* onStartShouldSetPanResponder: (evt, gestureState) => true,
|
||||
* onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
|
||||
* onMoveShouldSetPanResponder: (evt, gestureState) => true,
|
||||
* onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
|
||||
*
|
||||
* onPanResponderGrant: (evt, gestureState) => {
|
||||
* // The gesture has started. Show visual feedback so the user knows
|
||||
* // what is happening!
|
||||
*
|
||||
* // gestureState.d{x,y} will be set to zero now
|
||||
* },
|
||||
* onPanResponderMove: (evt, gestureState) => {
|
||||
* // The most recent move distance is gestureState.move{X,Y}
|
||||
*
|
||||
* // The accumulated gesture distance since becoming responder is
|
||||
* // gestureState.d{x,y}
|
||||
* },
|
||||
* onPanResponderTerminationRequest: (evt, gestureState) => true,
|
||||
* onPanResponderRelease: (evt, gestureState) => {
|
||||
* // The user has released all touches while this view is the
|
||||
* // responder. This typically means a gesture has succeeded
|
||||
* },
|
||||
* onPanResponderTerminate: (evt, gestureState) => {
|
||||
* // Another component has become the responder, so this gesture
|
||||
* // should be cancelled
|
||||
* },
|
||||
* onShouldBlockNativeResponder: (evt, gestureState) => {
|
||||
* // Returns whether this component should block native components from becoming the JS
|
||||
* // responder. Returns true by default. Is currently only supported on android.
|
||||
* return true;
|
||||
* },
|
||||
* });
|
||||
* },
|
||||
*
|
||||
* render: function() {
|
||||
* return (
|
||||
* <View {...this._panResponder.panHandlers} />
|
||||
* );
|
||||
* },
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* ### Working Example
|
||||
*
|
||||
* To see it in action, try the
|
||||
* [PanResponder example in RNTester](https://github.com/facebook/react-native/blob/master/RNTester/js/PanResponderExample.js)
|
||||
*/
|
||||
|
||||
export type GestureState = {|
|
||||
/**
|
||||
* ID of the gestureState - persisted as long as there at least one touch on screen
|
||||
*/
|
||||
stateID: number,
|
||||
|
||||
/**
|
||||
* The latest screen coordinates of the recently-moved touch
|
||||
*/
|
||||
moveX: number,
|
||||
|
||||
/**
|
||||
* The latest screen coordinates of the recently-moved touch
|
||||
*/
|
||||
moveY: number,
|
||||
|
||||
/**
|
||||
* The screen coordinates of the responder grant
|
||||
*/
|
||||
x0: number,
|
||||
|
||||
/**
|
||||
* The screen coordinates of the responder grant
|
||||
*/
|
||||
y0: number,
|
||||
|
||||
/**
|
||||
* Accumulated distance of the gesture since the touch started
|
||||
*/
|
||||
dx: number,
|
||||
|
||||
/**
|
||||
* Accumulated distance of the gesture since the touch started
|
||||
*/
|
||||
dy: number,
|
||||
|
||||
/**
|
||||
* Current velocity of the gesture
|
||||
*/
|
||||
vx: number,
|
||||
|
||||
/**
|
||||
* Current velocity of the gesture
|
||||
*/
|
||||
vy: number,
|
||||
|
||||
/**
|
||||
* Number of touches currently on screen
|
||||
*/
|
||||
numberActiveTouches: number,
|
||||
|
||||
/**
|
||||
* All `gestureState` accounts for timeStamps up until this value
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_accountsForMovesUpTo: number,
|
||||
|};
|
||||
|
||||
type ActiveCallback = (
|
||||
event: PressEvent,
|
||||
gestureState: GestureState,
|
||||
) => boolean;
|
||||
|
||||
type PassiveCallback = (event: PressEvent, gestureState: GestureState) => mixed;
|
||||
|
||||
type PanResponderConfig = $ReadOnly<{|
|
||||
onMoveShouldSetPanResponder?: ?ActiveCallback,
|
||||
onMoveShouldSetPanResponderCapture?: ?ActiveCallback,
|
||||
onStartShouldSetPanResponder?: ?ActiveCallback,
|
||||
onStartShouldSetPanResponderCapture?: ?ActiveCallback,
|
||||
/**
|
||||
* The body of `onResponderGrant` returns a bool, but the vast majority of
|
||||
* callsites return void and this TODO notice is found in it:
|
||||
* TODO: t7467124 investigate if this can be removed
|
||||
*/
|
||||
onPanResponderGrant?: ?(PassiveCallback | ActiveCallback),
|
||||
onPanResponderReject?: ?PassiveCallback,
|
||||
onPanResponderStart?: ?PassiveCallback,
|
||||
onPanResponderEnd?: ?PassiveCallback,
|
||||
onPanResponderRelease?: ?PassiveCallback,
|
||||
onPanResponderMove?: ?PassiveCallback,
|
||||
onPanResponderTerminate?: ?PassiveCallback,
|
||||
onPanResponderTerminationRequest?: ?ActiveCallback,
|
||||
onShouldBlockNativeResponder?: ?ActiveCallback,
|
||||
|}>;
|
||||
|
||||
const PanResponder = {
|
||||
/**
|
||||
*
|
||||
* A graphical explanation of the touch data flow:
|
||||
*
|
||||
* +----------------------------+ +--------------------------------+
|
||||
* | ResponderTouchHistoryStore | |TouchHistoryMath |
|
||||
* +----------------------------+ +----------+---------------------+
|
||||
* |Global store of touchHistory| |Allocation-less math util |
|
||||
* |including activeness, start | |on touch history (centroids |
|
||||
* |position, prev/cur position.| |and multitouch movement etc) |
|
||||
* | | | |
|
||||
* +----^-----------------------+ +----^---------------------------+
|
||||
* | |
|
||||
* | (records relevant history |
|
||||
* | of touches relevant for |
|
||||
* | implementing higher level |
|
||||
* | gestures) |
|
||||
* | |
|
||||
* +----+-----------------------+ +----|---------------------------+
|
||||
* | ResponderEventPlugin | | | Your App/Component |
|
||||
* +----------------------------+ +----|---------------------------+
|
||||
* |Negotiates which view gets | Low level | | High level |
|
||||
* |onResponderMove events. | events w/ | +-+-------+ events w/ |
|
||||
* |Also records history into | touchHistory| | Pan | multitouch + |
|
||||
* |ResponderTouchHistoryStore. +---------------->Responder+-----> accumulative|
|
||||
* +----------------------------+ attached to | | | distance and |
|
||||
* each event | +---------+ velocity. |
|
||||
* | |
|
||||
* | |
|
||||
* +--------------------------------+
|
||||
*
|
||||
*
|
||||
*
|
||||
* Gesture that calculates cumulative movement over time in a way that just
|
||||
* "does the right thing" for multiple touches. The "right thing" is very
|
||||
* nuanced. When moving two touches in opposite directions, the cumulative
|
||||
* distance is zero in each dimension. When two touches move in parallel five
|
||||
* pixels in the same direction, the cumulative distance is five, not ten. If
|
||||
* two touches start, one moves five in a direction, then stops and the other
|
||||
* touch moves fives in the same direction, the cumulative distance is ten.
|
||||
*
|
||||
* This logic requires a kind of processing of time "clusters" of touch events
|
||||
* so that two touch moves that essentially occur in parallel but move every
|
||||
* other frame respectively, are considered part of the same movement.
|
||||
*
|
||||
* Explanation of some of the non-obvious fields:
|
||||
*
|
||||
* - moveX/moveY: If no move event has been observed, then `(moveX, moveY)` is
|
||||
* invalid. If a move event has been observed, `(moveX, moveY)` is the
|
||||
* centroid of the most recently moved "cluster" of active touches.
|
||||
* (Currently all move have the same timeStamp, but later we should add some
|
||||
* threshold for what is considered to be "moving"). If a palm is
|
||||
* accidentally counted as a touch, but a finger is moving greatly, the palm
|
||||
* will move slightly, but we only want to count the single moving touch.
|
||||
* - x0/y0: Centroid location (non-cumulative) at the time of becoming
|
||||
* responder.
|
||||
* - dx/dy: Cumulative touch distance - not the same thing as sum of each touch
|
||||
* distance. Accounts for touch moves that are clustered together in time,
|
||||
* moving the same direction. Only valid when currently responder (otherwise,
|
||||
* it only represents the drag distance below the threshold).
|
||||
* - vx/vy: Velocity.
|
||||
*/
|
||||
|
||||
_initializeGestureState(gestureState: GestureState) {
|
||||
gestureState.moveX = 0;
|
||||
gestureState.moveY = 0;
|
||||
gestureState.x0 = 0;
|
||||
gestureState.y0 = 0;
|
||||
gestureState.dx = 0;
|
||||
gestureState.dy = 0;
|
||||
gestureState.vx = 0;
|
||||
gestureState.vy = 0;
|
||||
gestureState.numberActiveTouches = 0;
|
||||
// All `gestureState` accounts for timeStamps up until:
|
||||
gestureState._accountsForMovesUpTo = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* This is nuanced and is necessary. It is incorrect to continuously take all
|
||||
* active *and* recently moved touches, find the centroid, and track how that
|
||||
* result changes over time. Instead, we must take all recently moved
|
||||
* touches, and calculate how the centroid has changed just for those
|
||||
* recently moved touches, and append that change to an accumulator. This is
|
||||
* to (at least) handle the case where the user is moving three fingers, and
|
||||
* then one of the fingers stops but the other two continue.
|
||||
*
|
||||
* This is very different than taking all of the recently moved touches and
|
||||
* storing their centroid as `dx/dy`. For correctness, we must *accumulate
|
||||
* changes* in the centroid of recently moved touches.
|
||||
*
|
||||
* There is also some nuance with how we handle multiple moved touches in a
|
||||
* single event. With the way `ReactNativeEventEmitter` dispatches touches as
|
||||
* individual events, multiple touches generate two 'move' events, each of
|
||||
* them triggering `onResponderMove`. But with the way `PanResponder` works,
|
||||
* all of the gesture inference is performed on the first dispatch, since it
|
||||
* looks at all of the touches (even the ones for which there hasn't been a
|
||||
* native dispatch yet). Therefore, `PanResponder` does not call
|
||||
* `onResponderMove` passed the first dispatch. This diverges from the
|
||||
* typical responder callback pattern (without using `PanResponder`), but
|
||||
* avoids more dispatches than necessary.
|
||||
*/
|
||||
_updateGestureStateOnMove(
|
||||
gestureState: GestureState,
|
||||
touchHistory: $PropertyType<PressEvent, 'touchHistory'>,
|
||||
) {
|
||||
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
|
||||
gestureState.moveX = currentCentroidXOfTouchesChangedAfter(
|
||||
touchHistory,
|
||||
gestureState._accountsForMovesUpTo,
|
||||
);
|
||||
gestureState.moveY = currentCentroidYOfTouchesChangedAfter(
|
||||
touchHistory,
|
||||
gestureState._accountsForMovesUpTo,
|
||||
);
|
||||
const movedAfter = gestureState._accountsForMovesUpTo;
|
||||
const prevX = previousCentroidXOfTouchesChangedAfter(
|
||||
touchHistory,
|
||||
movedAfter,
|
||||
);
|
||||
const x = currentCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
const prevY = previousCentroidYOfTouchesChangedAfter(
|
||||
touchHistory,
|
||||
movedAfter,
|
||||
);
|
||||
const y = currentCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
const nextDX = gestureState.dx + (x - prevX);
|
||||
const nextDY = gestureState.dy + (y - prevY);
|
||||
|
||||
// TODO: This must be filtered intelligently.
|
||||
const dt =
|
||||
touchHistory.mostRecentTimeStamp - gestureState._accountsForMovesUpTo;
|
||||
gestureState.vx = (nextDX - gestureState.dx) / dt;
|
||||
gestureState.vy = (nextDY - gestureState.dy) / dt;
|
||||
|
||||
gestureState.dx = nextDX;
|
||||
gestureState.dy = nextDY;
|
||||
gestureState._accountsForMovesUpTo = touchHistory.mostRecentTimeStamp;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {object} config Enhanced versions of all of the responder callbacks
|
||||
* that provide not only the typical `ResponderSyntheticEvent`, but also the
|
||||
* `PanResponder` gesture state. Simply replace the word `Responder` with
|
||||
* `PanResponder` in each of the typical `onResponder*` callbacks. For
|
||||
* example, the `config` object would look like:
|
||||
*
|
||||
* - `onMoveShouldSetPanResponder: (e, gestureState) => {...}`
|
||||
* - `onMoveShouldSetPanResponderCapture: (e, gestureState) => {...}`
|
||||
* - `onStartShouldSetPanResponder: (e, gestureState) => {...}`
|
||||
* - `onStartShouldSetPanResponderCapture: (e, gestureState) => {...}`
|
||||
* - `onPanResponderReject: (e, gestureState) => {...}`
|
||||
* - `onPanResponderGrant: (e, gestureState) => {...}`
|
||||
* - `onPanResponderStart: (e, gestureState) => {...}`
|
||||
* - `onPanResponderEnd: (e, gestureState) => {...}`
|
||||
* - `onPanResponderRelease: (e, gestureState) => {...}`
|
||||
* - `onPanResponderMove: (e, gestureState) => {...}`
|
||||
* - `onPanResponderTerminate: (e, gestureState) => {...}`
|
||||
* - `onPanResponderTerminationRequest: (e, gestureState) => {...}`
|
||||
* - `onShouldBlockNativeResponder: (e, gestureState) => {...}`
|
||||
*
|
||||
* In general, for events that have capture equivalents, we update the
|
||||
* gestureState once in the capture phase and can use it in the bubble phase
|
||||
* as well.
|
||||
*
|
||||
* Be careful with onStartShould* callbacks. They only reflect updated
|
||||
* `gestureState` for start/end events that bubble/capture to the Node.
|
||||
* Once the node is the responder, you can rely on every start/end event
|
||||
* being processed by the gesture and `gestureState` being updated
|
||||
* accordingly. (numberActiveTouches) may not be totally accurate unless you
|
||||
* are the responder.
|
||||
*/
|
||||
create(
|
||||
config: PanResponderConfig,
|
||||
): $TEMPORARY$object<{|
|
||||
getInteractionHandle: () => ?number,
|
||||
panHandlers: $TEMPORARY$object<{|
|
||||
onMoveShouldSetResponder: (event: PressEvent) => boolean,
|
||||
onMoveShouldSetResponderCapture: (event: PressEvent) => boolean,
|
||||
onResponderEnd: (event: PressEvent) => void,
|
||||
onResponderGrant: (event: PressEvent) => boolean,
|
||||
onResponderMove: (event: PressEvent) => void,
|
||||
onResponderReject: (event: PressEvent) => void,
|
||||
onResponderRelease: (event: PressEvent) => void,
|
||||
onResponderStart: (event: PressEvent) => void,
|
||||
onResponderTerminate: (event: PressEvent) => void,
|
||||
onResponderTerminationRequest: (event: PressEvent) => boolean,
|
||||
onStartShouldSetResponder: (event: PressEvent) => boolean,
|
||||
onStartShouldSetResponderCapture: (event: PressEvent) => boolean,
|
||||
|}>,
|
||||
|}> {
|
||||
const interactionState = {
|
||||
handle: (null: ?number),
|
||||
};
|
||||
const gestureState: GestureState = {
|
||||
// Useful for debugging
|
||||
stateID: Math.random(),
|
||||
moveX: 0,
|
||||
moveY: 0,
|
||||
x0: 0,
|
||||
y0: 0,
|
||||
dx: 0,
|
||||
dy: 0,
|
||||
vx: 0,
|
||||
vy: 0,
|
||||
numberActiveTouches: 0,
|
||||
_accountsForMovesUpTo: 0,
|
||||
};
|
||||
const panHandlers = {
|
||||
onStartShouldSetResponder(event: PressEvent): boolean {
|
||||
return config.onStartShouldSetPanResponder == null
|
||||
? false
|
||||
: config.onStartShouldSetPanResponder(event, gestureState);
|
||||
},
|
||||
onMoveShouldSetResponder(event: PressEvent): boolean {
|
||||
return config.onMoveShouldSetPanResponder == null
|
||||
? false
|
||||
: config.onMoveShouldSetPanResponder(event, gestureState);
|
||||
},
|
||||
onStartShouldSetResponderCapture(event: PressEvent): boolean {
|
||||
// TODO: Actually, we should reinitialize the state any time
|
||||
// touches.length increases from 0 active to > 0 active.
|
||||
if (event.nativeEvent.touches.length === 1) {
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
}
|
||||
gestureState.numberActiveTouches =
|
||||
event.touchHistory.numberActiveTouches;
|
||||
return config.onStartShouldSetPanResponderCapture != null
|
||||
? config.onStartShouldSetPanResponderCapture(event, gestureState)
|
||||
: false;
|
||||
},
|
||||
|
||||
onMoveShouldSetResponderCapture(event: PressEvent): boolean {
|
||||
const touchHistory = event.touchHistory;
|
||||
// Responder system incorrectly dispatches should* to current responder
|
||||
// Filter out any touch moves past the first one - we would have
|
||||
// already processed multi-touch geometry during the first event.
|
||||
if (
|
||||
gestureState._accountsForMovesUpTo ===
|
||||
touchHistory.mostRecentTimeStamp
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
|
||||
return config.onMoveShouldSetPanResponderCapture
|
||||
? config.onMoveShouldSetPanResponderCapture(event, gestureState)
|
||||
: false;
|
||||
},
|
||||
|
||||
onResponderGrant(event: PressEvent): boolean {
|
||||
if (!interactionState.handle) {
|
||||
interactionState.handle = InteractionManager.createInteractionHandle();
|
||||
}
|
||||
gestureState.x0 = currentCentroidX(event.touchHistory);
|
||||
gestureState.y0 = currentCentroidY(event.touchHistory);
|
||||
gestureState.dx = 0;
|
||||
gestureState.dy = 0;
|
||||
if (config.onPanResponderGrant) {
|
||||
config.onPanResponderGrant(event, gestureState);
|
||||
}
|
||||
// TODO: t7467124 investigate if this can be removed
|
||||
return config.onShouldBlockNativeResponder == null
|
||||
? true
|
||||
: config.onShouldBlockNativeResponder(event, gestureState);
|
||||
},
|
||||
|
||||
onResponderReject(event: PressEvent): void {
|
||||
clearInteractionHandle(
|
||||
interactionState,
|
||||
config.onPanResponderReject,
|
||||
event,
|
||||
gestureState,
|
||||
);
|
||||
},
|
||||
|
||||
onResponderRelease(event: PressEvent): void {
|
||||
clearInteractionHandle(
|
||||
interactionState,
|
||||
config.onPanResponderRelease,
|
||||
event,
|
||||
gestureState,
|
||||
);
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
},
|
||||
|
||||
onResponderStart(event: PressEvent): void {
|
||||
const touchHistory = event.touchHistory;
|
||||
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
|
||||
if (config.onPanResponderStart) {
|
||||
config.onPanResponderStart(event, gestureState);
|
||||
}
|
||||
},
|
||||
|
||||
onResponderMove(event: PressEvent): void {
|
||||
const touchHistory = event.touchHistory;
|
||||
// Guard against the dispatch of two touch moves when there are two
|
||||
// simultaneously changed touches.
|
||||
if (
|
||||
gestureState._accountsForMovesUpTo ===
|
||||
touchHistory.mostRecentTimeStamp
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// Filter out any touch moves past the first one - we would have
|
||||
// already processed multi-touch geometry during the first event.
|
||||
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
|
||||
if (config.onPanResponderMove) {
|
||||
config.onPanResponderMove(event, gestureState);
|
||||
}
|
||||
},
|
||||
|
||||
onResponderEnd(event: PressEvent): void {
|
||||
const touchHistory = event.touchHistory;
|
||||
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
|
||||
clearInteractionHandle(
|
||||
interactionState,
|
||||
config.onPanResponderEnd,
|
||||
event,
|
||||
gestureState,
|
||||
);
|
||||
},
|
||||
|
||||
onResponderTerminate(event: PressEvent): void {
|
||||
clearInteractionHandle(
|
||||
interactionState,
|
||||
config.onPanResponderTerminate,
|
||||
event,
|
||||
gestureState,
|
||||
);
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
},
|
||||
|
||||
onResponderTerminationRequest(event: PressEvent): boolean {
|
||||
return config.onPanResponderTerminationRequest == null
|
||||
? true
|
||||
: config.onPanResponderTerminationRequest(event, gestureState);
|
||||
},
|
||||
};
|
||||
return {
|
||||
panHandlers,
|
||||
getInteractionHandle(): ?number {
|
||||
return interactionState.handle;
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
function clearInteractionHandle(
|
||||
interactionState: {handle: ?number, ...},
|
||||
callback: ?(ActiveCallback | PassiveCallback),
|
||||
event: PressEvent,
|
||||
gestureState: GestureState,
|
||||
) {
|
||||
if (interactionState.handle) {
|
||||
InteractionManager.clearInteractionHandle(interactionState.handle);
|
||||
interactionState.handle = null;
|
||||
}
|
||||
if (callback) {
|
||||
callback(event, gestureState);
|
||||
}
|
||||
}
|
||||
|
||||
export type PanResponderInstance = $Call<
|
||||
$PropertyType<typeof PanResponder, 'create'>,
|
||||
PanResponderConfig,
|
||||
>;
|
||||
|
||||
module.exports = PanResponder;
|
184
node_modules/react-native/Libraries/Interaction/TaskQueue.js
generated
vendored
Normal file
184
node_modules/react-native/Libraries/Interaction/TaskQueue.js
generated
vendored
Normal file
@ -0,0 +1,184 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const infoLog = require('../Utilities/infoLog');
|
||||
const invariant = require('invariant');
|
||||
|
||||
type SimpleTask = {
|
||||
name: string,
|
||||
run: () => void,
|
||||
...
|
||||
};
|
||||
type PromiseTask = {
|
||||
name: string,
|
||||
gen: () => Promise<any>,
|
||||
...
|
||||
};
|
||||
export type Task = Function | SimpleTask | PromiseTask;
|
||||
|
||||
const DEBUG: false = false;
|
||||
|
||||
/**
|
||||
* TaskQueue - A system for queueing and executing a mix of simple callbacks and
|
||||
* trees of dependent tasks based on Promises. No tasks are executed unless
|
||||
* `processNext` is called.
|
||||
*
|
||||
* `enqueue` takes a Task object with either a simple `run` callback, or a
|
||||
* `gen` function that returns a `Promise` and puts it in the queue. If a gen
|
||||
* function is supplied, then the promise it returns will block execution of
|
||||
* tasks already in the queue until it resolves. This can be used to make sure
|
||||
* the first task is fully resolved (including asynchronous dependencies that
|
||||
* also schedule more tasks via `enqueue`) before starting on the next task.
|
||||
* The `onMoreTasks` constructor argument is used to inform the owner that an
|
||||
* async task has resolved and that the queue should be processed again.
|
||||
*
|
||||
* Note: Tasks are only actually executed with explicit calls to `processNext`.
|
||||
*/
|
||||
class TaskQueue {
|
||||
/**
|
||||
* TaskQueue instances are self contained and independent, so multiple tasks
|
||||
* of varying semantics and priority can operate together.
|
||||
*
|
||||
* `onMoreTasks` is invoked when `PromiseTask`s resolve if there are more
|
||||
* tasks to process.
|
||||
*/
|
||||
constructor({onMoreTasks}: {onMoreTasks: () => void, ...}) {
|
||||
this._onMoreTasks = onMoreTasks;
|
||||
this._queueStack = [{tasks: [], popable: false}];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a task to the queue. It is recommended to name your tasks for easier
|
||||
* async debugging. Tasks will not be executed until `processNext` is called
|
||||
* explicitly.
|
||||
*/
|
||||
enqueue(task: Task): void {
|
||||
this._getCurrentQueue().push(task);
|
||||
}
|
||||
|
||||
enqueueTasks(tasks: Array<Task>): void {
|
||||
tasks.forEach(task => this.enqueue(task));
|
||||
}
|
||||
|
||||
cancelTasks(tasksToCancel: Array<Task>): void {
|
||||
// search through all tasks and remove them.
|
||||
this._queueStack = this._queueStack
|
||||
.map(queue => ({
|
||||
...queue,
|
||||
tasks: queue.tasks.filter(task => tasksToCancel.indexOf(task) === -1),
|
||||
}))
|
||||
.filter((queue, idx) => queue.tasks.length > 0 || idx === 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if `processNext` should be called.
|
||||
*
|
||||
* @returns {boolean} Returns true if there are tasks that are ready to be
|
||||
* processed with `processNext`, or returns false if there are no more tasks
|
||||
* to be processed right now, although there may be tasks in the queue that
|
||||
* are blocked by earlier `PromiseTask`s that haven't resolved yet.
|
||||
* `onMoreTasks` will be called after each `PromiseTask` resolves if there are
|
||||
* tasks ready to run at that point.
|
||||
*/
|
||||
hasTasksToProcess(): boolean {
|
||||
return this._getCurrentQueue().length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the next task in the queue.
|
||||
*/
|
||||
processNext(): void {
|
||||
const queue = this._getCurrentQueue();
|
||||
if (queue.length) {
|
||||
const task = queue.shift();
|
||||
try {
|
||||
if (task.gen) {
|
||||
DEBUG && infoLog('TaskQueue: genPromise for task ' + task.name);
|
||||
this._genPromise((task: any)); // Rather than annoying tagged union
|
||||
} else if (task.run) {
|
||||
DEBUG && infoLog('TaskQueue: run task ' + task.name);
|
||||
task.run();
|
||||
} else {
|
||||
invariant(
|
||||
typeof task === 'function',
|
||||
'Expected Function, SimpleTask, or PromiseTask, but got:\n' +
|
||||
JSON.stringify(task, null, 2),
|
||||
);
|
||||
DEBUG && infoLog('TaskQueue: run anonymous task');
|
||||
task();
|
||||
}
|
||||
} catch (e) {
|
||||
e.message =
|
||||
'TaskQueue: Error with task ' + (task.name || '') + ': ' + e.message;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_queueStack: Array<{
|
||||
tasks: Array<Task>,
|
||||
popable: boolean,
|
||||
...
|
||||
}>;
|
||||
_onMoreTasks: () => void;
|
||||
|
||||
_getCurrentQueue(): Array<Task> {
|
||||
const stackIdx = this._queueStack.length - 1;
|
||||
const queue = this._queueStack[stackIdx];
|
||||
if (
|
||||
queue.popable &&
|
||||
queue.tasks.length === 0 &&
|
||||
this._queueStack.length > 1
|
||||
) {
|
||||
this._queueStack.pop();
|
||||
DEBUG &&
|
||||
infoLog('TaskQueue: popped queue: ', {
|
||||
stackIdx,
|
||||
queueStackSize: this._queueStack.length,
|
||||
});
|
||||
return this._getCurrentQueue();
|
||||
} else {
|
||||
return queue.tasks;
|
||||
}
|
||||
}
|
||||
|
||||
_genPromise(task: PromiseTask) {
|
||||
// Each async task pushes it's own queue onto the queue stack. This
|
||||
// effectively defers execution of previously queued tasks until the promise
|
||||
// resolves, at which point we allow the new queue to be popped, which
|
||||
// happens once it is fully processed.
|
||||
this._queueStack.push({tasks: [], popable: false});
|
||||
const stackIdx = this._queueStack.length - 1;
|
||||
DEBUG && infoLog('TaskQueue: push new queue: ', {stackIdx});
|
||||
DEBUG && infoLog('TaskQueue: exec gen task ' + task.name);
|
||||
task
|
||||
.gen()
|
||||
.then(() => {
|
||||
DEBUG &&
|
||||
infoLog('TaskQueue: onThen for gen task ' + task.name, {
|
||||
stackIdx,
|
||||
queueStackSize: this._queueStack.length,
|
||||
});
|
||||
this._queueStack[stackIdx].popable = true;
|
||||
this.hasTasksToProcess() && this._onMoreTasks();
|
||||
})
|
||||
.catch(ex => {
|
||||
ex.message = `TaskQueue: Error resolving Promise in task ${
|
||||
task.name
|
||||
}: ${ex.message}`;
|
||||
throw ex;
|
||||
})
|
||||
.done();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TaskQueue;
|
153
node_modules/react-native/Libraries/Interaction/TouchHistoryMath.js
generated
vendored
Normal file
153
node_modules/react-native/Libraries/Interaction/TouchHistoryMath.js
generated
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
const TouchHistoryMath = {
|
||||
/**
|
||||
* This code is optimized and not intended to look beautiful. This allows
|
||||
* computing of touch centroids that have moved after `touchesChangedAfter`
|
||||
* timeStamp. You can compute the current centroid involving all touches
|
||||
* moves after `touchesChangedAfter`, or you can compute the previous
|
||||
* centroid of all touches that were moved after `touchesChangedAfter`.
|
||||
*
|
||||
* @param {TouchHistoryMath} touchHistory Standard Responder touch track
|
||||
* data.
|
||||
* @param {number} touchesChangedAfter timeStamp after which moved touches
|
||||
* are considered "actively moving" - not just "active".
|
||||
* @param {boolean} isXAxis Consider `x` dimension vs. `y` dimension.
|
||||
* @param {boolean} ofCurrent Compute current centroid for actively moving
|
||||
* touches vs. previous centroid of now actively moving touches.
|
||||
* @return {number} value of centroid in specified dimension.
|
||||
*/
|
||||
centroidDimension: function(
|
||||
touchHistory,
|
||||
touchesChangedAfter,
|
||||
isXAxis,
|
||||
ofCurrent,
|
||||
) {
|
||||
const touchBank = touchHistory.touchBank;
|
||||
let total = 0;
|
||||
let count = 0;
|
||||
|
||||
const oneTouchData =
|
||||
touchHistory.numberActiveTouches === 1
|
||||
? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch]
|
||||
: null;
|
||||
|
||||
if (oneTouchData !== null) {
|
||||
if (
|
||||
oneTouchData.touchActive &&
|
||||
oneTouchData.currentTimeStamp > touchesChangedAfter
|
||||
) {
|
||||
total +=
|
||||
ofCurrent && isXAxis
|
||||
? oneTouchData.currentPageX
|
||||
: ofCurrent && !isXAxis
|
||||
? oneTouchData.currentPageY
|
||||
: !ofCurrent && isXAxis
|
||||
? oneTouchData.previousPageX
|
||||
: oneTouchData.previousPageY;
|
||||
count = 1;
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < touchBank.length; i++) {
|
||||
const touchTrack = touchBank[i];
|
||||
if (
|
||||
touchTrack !== null &&
|
||||
touchTrack !== undefined &&
|
||||
touchTrack.touchActive &&
|
||||
touchTrack.currentTimeStamp >= touchesChangedAfter
|
||||
) {
|
||||
let toAdd; // Yuck, program temporarily in invalid state.
|
||||
if (ofCurrent && isXAxis) {
|
||||
toAdd = touchTrack.currentPageX;
|
||||
} else if (ofCurrent && !isXAxis) {
|
||||
toAdd = touchTrack.currentPageY;
|
||||
} else if (!ofCurrent && isXAxis) {
|
||||
toAdd = touchTrack.previousPageX;
|
||||
} else {
|
||||
toAdd = touchTrack.previousPageY;
|
||||
}
|
||||
total += toAdd;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count > 0 ? total / count : TouchHistoryMath.noCentroid;
|
||||
},
|
||||
|
||||
currentCentroidXOfTouchesChangedAfter: function(
|
||||
touchHistory,
|
||||
touchesChangedAfter,
|
||||
) {
|
||||
return TouchHistoryMath.centroidDimension(
|
||||
touchHistory,
|
||||
touchesChangedAfter,
|
||||
true, // isXAxis
|
||||
true, // ofCurrent
|
||||
);
|
||||
},
|
||||
|
||||
currentCentroidYOfTouchesChangedAfter: function(
|
||||
touchHistory,
|
||||
touchesChangedAfter,
|
||||
) {
|
||||
return TouchHistoryMath.centroidDimension(
|
||||
touchHistory,
|
||||
touchesChangedAfter,
|
||||
false, // isXAxis
|
||||
true, // ofCurrent
|
||||
);
|
||||
},
|
||||
|
||||
previousCentroidXOfTouchesChangedAfter: function(
|
||||
touchHistory,
|
||||
touchesChangedAfter,
|
||||
) {
|
||||
return TouchHistoryMath.centroidDimension(
|
||||
touchHistory,
|
||||
touchesChangedAfter,
|
||||
true, // isXAxis
|
||||
false, // ofCurrent
|
||||
);
|
||||
},
|
||||
|
||||
previousCentroidYOfTouchesChangedAfter: function(
|
||||
touchHistory,
|
||||
touchesChangedAfter,
|
||||
) {
|
||||
return TouchHistoryMath.centroidDimension(
|
||||
touchHistory,
|
||||
touchesChangedAfter,
|
||||
false, // isXAxis
|
||||
false, // ofCurrent
|
||||
);
|
||||
},
|
||||
|
||||
currentCentroidX: function(touchHistory) {
|
||||
return TouchHistoryMath.centroidDimension(
|
||||
touchHistory,
|
||||
0, // touchesChangedAfter
|
||||
true, // isXAxis
|
||||
true, // ofCurrent
|
||||
);
|
||||
},
|
||||
|
||||
currentCentroidY: function(touchHistory) {
|
||||
return TouchHistoryMath.centroidDimension(
|
||||
touchHistory,
|
||||
0, // touchesChangedAfter
|
||||
false, // isXAxis
|
||||
true, // ofCurrent
|
||||
);
|
||||
},
|
||||
|
||||
noCentroid: -1,
|
||||
};
|
||||
|
||||
module.exports = TouchHistoryMath;
|
Reference in New Issue
Block a user