Use named exports in more places (#11457)
* Convert EventPlugin{Hub,Registry} to named exports * Convert EventPluginUtils to named exports * Convert EventPropagators to named exports * Convert ReactControlledComponent to named exports * Convert ReactGenericBatching to named exports * Convert ReactDOMComponentTree to named exports * Convert ReactNativeComponentTree to named exports * Convert ReactNativeRTComponentTree to named exports * Convert FallbackCompositionState to named exports * Convert ReactEventEmitterMixin to named exports * Convert ReactBrowserEventEmitter to named exports * Convert ReactNativeEventEmitter to named exports * Convert ReactDOMEventListener to named exports * Convert DOMMarkupOperations to named exports * Convert DOMProperty to named exports * Add suppression for existing Flow violation Flow didn't see it before. * Update sizes
This commit is contained in:
parent
7432013872
commit
92b7b172cc
|
@ -8,8 +8,15 @@
|
|||
import ReactErrorUtils from 'shared/ReactErrorUtils';
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
|
||||
import EventPluginRegistry from './EventPluginRegistry';
|
||||
import EventPluginUtils from './EventPluginUtils';
|
||||
import {
|
||||
injectEventPluginOrder,
|
||||
injectEventPluginsByName,
|
||||
plugins,
|
||||
} from './EventPluginRegistry';
|
||||
import {
|
||||
executeDispatchesInOrder,
|
||||
getFiberCurrentPropsFromNode,
|
||||
} from './EventPluginUtils';
|
||||
import accumulateInto from './accumulateInto';
|
||||
import forEachAccumulated from './forEachAccumulated';
|
||||
|
||||
|
@ -28,7 +35,7 @@ var eventQueue = null;
|
|||
*/
|
||||
var executeDispatchesAndRelease = function(event, simulated) {
|
||||
if (event) {
|
||||
EventPluginUtils.executeDispatchesInOrder(event, simulated);
|
||||
executeDispatchesInOrder(event, simulated);
|
||||
|
||||
if (!event.isPersistent()) {
|
||||
event.constructor.release(event);
|
||||
|
@ -91,131 +98,127 @@ function shouldPreventMouseEvent(name, type, props) {
|
|||
*
|
||||
* @public
|
||||
*/
|
||||
var EventPluginHub = {
|
||||
/**
|
||||
* Methods for injecting dependencies.
|
||||
*/
|
||||
injection: {
|
||||
/**
|
||||
* @param {array} InjectedEventPluginOrder
|
||||
* @public
|
||||
*/
|
||||
injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder,
|
||||
|
||||
/**
|
||||
* @param {object} injectedNamesToPlugins Map from names to plugin modules.
|
||||
*/
|
||||
injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName,
|
||||
},
|
||||
/**
|
||||
* Methods for injecting dependencies.
|
||||
*/
|
||||
export const injection = {
|
||||
/**
|
||||
* @param {array} InjectedEventPluginOrder
|
||||
* @public
|
||||
*/
|
||||
injectEventPluginOrder,
|
||||
|
||||
/**
|
||||
* @param {object} inst The instance, which is the source of events.
|
||||
* @param {string} registrationName Name of listener (e.g. `onClick`).
|
||||
* @return {?function} The stored callback.
|
||||
* @param {object} injectedNamesToPlugins Map from names to plugin modules.
|
||||
*/
|
||||
getListener: function(inst, registrationName) {
|
||||
var listener;
|
||||
|
||||
// TODO: shouldPreventMouseEvent is DOM-specific and definitely should not
|
||||
// live here; needs to be moved to a better place soon
|
||||
const stateNode = inst.stateNode;
|
||||
if (!stateNode) {
|
||||
// Work in progress (ex: onload events in incremental mode).
|
||||
return null;
|
||||
}
|
||||
const props = EventPluginUtils.getFiberCurrentPropsFromNode(stateNode);
|
||||
if (!props) {
|
||||
// Work in progress.
|
||||
return null;
|
||||
}
|
||||
listener = props[registrationName];
|
||||
if (shouldPreventMouseEvent(registrationName, inst.type, props)) {
|
||||
return null;
|
||||
}
|
||||
invariant(
|
||||
!listener || typeof listener === 'function',
|
||||
'Expected `%s` listener to be a function, instead got a value of `%s` type.',
|
||||
registrationName,
|
||||
typeof listener,
|
||||
);
|
||||
return listener;
|
||||
},
|
||||
|
||||
/**
|
||||
* Allows registered plugins an opportunity to extract events from top-level
|
||||
* native browser events.
|
||||
*
|
||||
* @return {*} An accumulation of synthetic events.
|
||||
* @internal
|
||||
*/
|
||||
extractEvents: function(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
) {
|
||||
var events;
|
||||
var plugins = EventPluginRegistry.plugins;
|
||||
for (var i = 0; i < plugins.length; i++) {
|
||||
// Not every plugin in the ordering may be loaded at runtime.
|
||||
var possiblePlugin = plugins[i];
|
||||
if (possiblePlugin) {
|
||||
var extractedEvents = possiblePlugin.extractEvents(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
if (extractedEvents) {
|
||||
events = accumulateInto(events, extractedEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
return events;
|
||||
},
|
||||
|
||||
/**
|
||||
* Enqueues a synthetic event that should be dispatched when
|
||||
* `processEventQueue` is invoked.
|
||||
*
|
||||
* @param {*} events An accumulation of synthetic events.
|
||||
* @internal
|
||||
*/
|
||||
enqueueEvents: function(events) {
|
||||
if (events) {
|
||||
eventQueue = accumulateInto(eventQueue, events);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Dispatches all synthetic events on the event queue.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
processEventQueue: function(simulated) {
|
||||
// Set `eventQueue` to null before processing it so that we can tell if more
|
||||
// events get enqueued while processing.
|
||||
var processingEventQueue = eventQueue;
|
||||
eventQueue = null;
|
||||
if (simulated) {
|
||||
forEachAccumulated(
|
||||
processingEventQueue,
|
||||
executeDispatchesAndReleaseSimulated,
|
||||
);
|
||||
} else {
|
||||
forEachAccumulated(
|
||||
processingEventQueue,
|
||||
executeDispatchesAndReleaseTopLevel,
|
||||
);
|
||||
}
|
||||
invariant(
|
||||
!eventQueue,
|
||||
'processEventQueue(): Additional events were enqueued while processing ' +
|
||||
'an event queue. Support for this has not yet been implemented.',
|
||||
);
|
||||
// This would be a good time to rethrow if any of the event handlers threw.
|
||||
ReactErrorUtils.rethrowCaughtError();
|
||||
},
|
||||
injectEventPluginsByName,
|
||||
};
|
||||
|
||||
export default EventPluginHub;
|
||||
/**
|
||||
* @param {object} inst The instance, which is the source of events.
|
||||
* @param {string} registrationName Name of listener (e.g. `onClick`).
|
||||
* @return {?function} The stored callback.
|
||||
*/
|
||||
export function getListener(inst, registrationName) {
|
||||
var listener;
|
||||
|
||||
// TODO: shouldPreventMouseEvent is DOM-specific and definitely should not
|
||||
// live here; needs to be moved to a better place soon
|
||||
const stateNode = inst.stateNode;
|
||||
if (!stateNode) {
|
||||
// Work in progress (ex: onload events in incremental mode).
|
||||
return null;
|
||||
}
|
||||
const props = getFiberCurrentPropsFromNode(stateNode);
|
||||
if (!props) {
|
||||
// Work in progress.
|
||||
return null;
|
||||
}
|
||||
listener = props[registrationName];
|
||||
if (shouldPreventMouseEvent(registrationName, inst.type, props)) {
|
||||
return null;
|
||||
}
|
||||
invariant(
|
||||
!listener || typeof listener === 'function',
|
||||
'Expected `%s` listener to be a function, instead got a value of `%s` type.',
|
||||
registrationName,
|
||||
typeof listener,
|
||||
);
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows registered plugins an opportunity to extract events from top-level
|
||||
* native browser events.
|
||||
*
|
||||
* @return {*} An accumulation of synthetic events.
|
||||
* @internal
|
||||
*/
|
||||
export function extractEvents(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
) {
|
||||
var events;
|
||||
for (var i = 0; i < plugins.length; i++) {
|
||||
// Not every plugin in the ordering may be loaded at runtime.
|
||||
var possiblePlugin = plugins[i];
|
||||
if (possiblePlugin) {
|
||||
var extractedEvents = possiblePlugin.extractEvents(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
if (extractedEvents) {
|
||||
events = accumulateInto(events, extractedEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues a synthetic event that should be dispatched when
|
||||
* `processEventQueue` is invoked.
|
||||
*
|
||||
* @param {*} events An accumulation of synthetic events.
|
||||
* @internal
|
||||
*/
|
||||
export function enqueueEvents(events) {
|
||||
if (events) {
|
||||
eventQueue = accumulateInto(eventQueue, events);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches all synthetic events on the event queue.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function processEventQueue(simulated) {
|
||||
// Set `eventQueue` to null before processing it so that we can tell if more
|
||||
// events get enqueued while processing.
|
||||
var processingEventQueue = eventQueue;
|
||||
eventQueue = null;
|
||||
if (simulated) {
|
||||
forEachAccumulated(
|
||||
processingEventQueue,
|
||||
executeDispatchesAndReleaseSimulated,
|
||||
);
|
||||
} else {
|
||||
forEachAccumulated(
|
||||
processingEventQueue,
|
||||
executeDispatchesAndReleaseTopLevel,
|
||||
);
|
||||
}
|
||||
invariant(
|
||||
!eventQueue,
|
||||
'processEventQueue(): Additional events were enqueued while processing ' +
|
||||
'an event queue. Support for this has not yet been implemented.',
|
||||
);
|
||||
// This would be a good time to rethrow if any of the event handlers threw.
|
||||
ReactErrorUtils.rethrowCaughtError();
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ function recomputePluginOrdering(): void {
|
|||
'the plugin ordering, `%s`.',
|
||||
pluginName,
|
||||
);
|
||||
if (EventPluginRegistry.plugins[pluginIndex]) {
|
||||
if (plugins[pluginIndex]) {
|
||||
continue;
|
||||
}
|
||||
invariant(
|
||||
|
@ -57,7 +57,7 @@ function recomputePluginOrdering(): void {
|
|||
'method, but `%s` does not.',
|
||||
pluginName,
|
||||
);
|
||||
EventPluginRegistry.plugins[pluginIndex] = pluginModule;
|
||||
plugins[pluginIndex] = pluginModule;
|
||||
var publishedEvents = pluginModule.eventTypes;
|
||||
for (var eventName in publishedEvents) {
|
||||
invariant(
|
||||
|
@ -88,12 +88,12 @@ function publishEventForPlugin(
|
|||
eventName: string,
|
||||
): boolean {
|
||||
invariant(
|
||||
!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName),
|
||||
!eventNameDispatchConfigs.hasOwnProperty(eventName),
|
||||
'EventPluginHub: More than one plugin attempted to publish the same ' +
|
||||
'event name, `%s`.',
|
||||
eventName,
|
||||
);
|
||||
EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig;
|
||||
eventNameDispatchConfigs[eventName] = dispatchConfig;
|
||||
|
||||
var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
|
||||
if (phasedRegistrationNames) {
|
||||
|
@ -132,23 +132,21 @@ function publishRegistrationName(
|
|||
eventName: string,
|
||||
): void {
|
||||
invariant(
|
||||
!EventPluginRegistry.registrationNameModules[registrationName],
|
||||
!registrationNameModules[registrationName],
|
||||
'EventPluginHub: More than one plugin attempted to publish the same ' +
|
||||
'registration name, `%s`.',
|
||||
registrationName,
|
||||
);
|
||||
EventPluginRegistry.registrationNameModules[registrationName] = pluginModule;
|
||||
EventPluginRegistry.registrationNameDependencies[registrationName] =
|
||||
registrationNameModules[registrationName] = pluginModule;
|
||||
registrationNameDependencies[registrationName] =
|
||||
pluginModule.eventTypes[eventName].dependencies;
|
||||
|
||||
if (__DEV__) {
|
||||
var lowerCasedName = registrationName.toLowerCase();
|
||||
EventPluginRegistry.possibleRegistrationNames[
|
||||
lowerCasedName
|
||||
] = registrationName;
|
||||
possibleRegistrationNames[lowerCasedName] = registrationName;
|
||||
|
||||
if (registrationName === 'onDoubleClick') {
|
||||
EventPluginRegistry.possibleRegistrationNames.ondblclick = registrationName;
|
||||
possibleRegistrationNames.ondblclick = registrationName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,95 +156,92 @@ function publishRegistrationName(
|
|||
*
|
||||
* @see {EventPluginHub}
|
||||
*/
|
||||
var EventPluginRegistry = {
|
||||
/**
|
||||
* Ordered list of injected plugins.
|
||||
*/
|
||||
plugins: [],
|
||||
|
||||
/**
|
||||
* Mapping from event name to dispatch config
|
||||
*/
|
||||
eventNameDispatchConfigs: {},
|
||||
/**
|
||||
* Ordered list of injected plugins.
|
||||
*/
|
||||
export const plugins = [];
|
||||
|
||||
/**
|
||||
* Mapping from registration name to plugin module
|
||||
*/
|
||||
registrationNameModules: {},
|
||||
/**
|
||||
* Mapping from event name to dispatch config
|
||||
*/
|
||||
export const eventNameDispatchConfigs = {};
|
||||
|
||||
/**
|
||||
* Mapping from registration name to event name
|
||||
*/
|
||||
registrationNameDependencies: {},
|
||||
/**
|
||||
* Mapping from registration name to plugin module
|
||||
*/
|
||||
export const registrationNameModules = {};
|
||||
|
||||
/**
|
||||
* Mapping from lowercase registration names to the properly cased version,
|
||||
* used to warn in the case of missing event handlers. Available
|
||||
* only in __DEV__.
|
||||
* @type {Object}
|
||||
*/
|
||||
possibleRegistrationNames: __DEV__ ? {} : (null: any),
|
||||
// Trust the developer to only use possibleRegistrationNames in __DEV__
|
||||
/**
|
||||
* Mapping from registration name to event name
|
||||
*/
|
||||
export const registrationNameDependencies = {};
|
||||
|
||||
/**
|
||||
* Injects an ordering of plugins (by plugin name). This allows the ordering
|
||||
* to be decoupled from injection of the actual plugins so that ordering is
|
||||
* always deterministic regardless of packaging, on-the-fly injection, etc.
|
||||
*
|
||||
* @param {array} InjectedEventPluginOrder
|
||||
* @internal
|
||||
* @see {EventPluginHub.injection.injectEventPluginOrder}
|
||||
*/
|
||||
injectEventPluginOrder: function(
|
||||
injectedEventPluginOrder: EventPluginOrder,
|
||||
): void {
|
||||
invariant(
|
||||
!eventPluginOrder,
|
||||
'EventPluginRegistry: Cannot inject event plugin ordering more than ' +
|
||||
'once. You are likely trying to load more than one copy of React.',
|
||||
);
|
||||
// Clone the ordering so it cannot be dynamically mutated.
|
||||
eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder);
|
||||
/**
|
||||
* Mapping from lowercase registration names to the properly cased version,
|
||||
* used to warn in the case of missing event handlers. Available
|
||||
* only in __DEV__.
|
||||
* @type {Object}
|
||||
*/
|
||||
export const possibleRegistrationNames = __DEV__ ? {} : (null: any);
|
||||
// Trust the developer to only use possibleRegistrationNames in __DEV__
|
||||
|
||||
/**
|
||||
* Injects an ordering of plugins (by plugin name). This allows the ordering
|
||||
* to be decoupled from injection of the actual plugins so that ordering is
|
||||
* always deterministic regardless of packaging, on-the-fly injection, etc.
|
||||
*
|
||||
* @param {array} InjectedEventPluginOrder
|
||||
* @internal
|
||||
* @see {EventPluginHub.injection.injectEventPluginOrder}
|
||||
*/
|
||||
export function injectEventPluginOrder(
|
||||
injectedEventPluginOrder: EventPluginOrder,
|
||||
): void {
|
||||
invariant(
|
||||
!eventPluginOrder,
|
||||
'EventPluginRegistry: Cannot inject event plugin ordering more than ' +
|
||||
'once. You are likely trying to load more than one copy of React.',
|
||||
);
|
||||
// Clone the ordering so it cannot be dynamically mutated.
|
||||
eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder);
|
||||
recomputePluginOrdering();
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects plugins to be used by `EventPluginHub`. The plugin names must be
|
||||
* in the ordering injected by `injectEventPluginOrder`.
|
||||
*
|
||||
* Plugins can be injected as part of page initialization or on-the-fly.
|
||||
*
|
||||
* @param {object} injectedNamesToPlugins Map from names to plugin modules.
|
||||
* @internal
|
||||
* @see {EventPluginHub.injection.injectEventPluginsByName}
|
||||
*/
|
||||
export function injectEventPluginsByName(
|
||||
injectedNamesToPlugins: NamesToPlugins,
|
||||
): void {
|
||||
var isOrderingDirty = false;
|
||||
for (var pluginName in injectedNamesToPlugins) {
|
||||
if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) {
|
||||
continue;
|
||||
}
|
||||
var pluginModule = injectedNamesToPlugins[pluginName];
|
||||
if (
|
||||
!namesToPlugins.hasOwnProperty(pluginName) ||
|
||||
namesToPlugins[pluginName] !== pluginModule
|
||||
) {
|
||||
invariant(
|
||||
!namesToPlugins[pluginName],
|
||||
'EventPluginRegistry: Cannot inject two different event plugins ' +
|
||||
'using the same name, `%s`.',
|
||||
pluginName,
|
||||
);
|
||||
namesToPlugins[pluginName] = pluginModule;
|
||||
isOrderingDirty = true;
|
||||
}
|
||||
}
|
||||
if (isOrderingDirty) {
|
||||
recomputePluginOrdering();
|
||||
},
|
||||
|
||||
/**
|
||||
* Injects plugins to be used by `EventPluginHub`. The plugin names must be
|
||||
* in the ordering injected by `injectEventPluginOrder`.
|
||||
*
|
||||
* Plugins can be injected as part of page initialization or on-the-fly.
|
||||
*
|
||||
* @param {object} injectedNamesToPlugins Map from names to plugin modules.
|
||||
* @internal
|
||||
* @see {EventPluginHub.injection.injectEventPluginsByName}
|
||||
*/
|
||||
injectEventPluginsByName: function(
|
||||
injectedNamesToPlugins: NamesToPlugins,
|
||||
): void {
|
||||
var isOrderingDirty = false;
|
||||
for (var pluginName in injectedNamesToPlugins) {
|
||||
if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) {
|
||||
continue;
|
||||
}
|
||||
var pluginModule = injectedNamesToPlugins[pluginName];
|
||||
if (
|
||||
!namesToPlugins.hasOwnProperty(pluginName) ||
|
||||
namesToPlugins[pluginName] !== pluginModule
|
||||
) {
|
||||
invariant(
|
||||
!namesToPlugins[pluginName],
|
||||
'EventPluginRegistry: Cannot inject two different event plugins ' +
|
||||
'using the same name, `%s`.',
|
||||
pluginName,
|
||||
);
|
||||
namesToPlugins[pluginName] = pluginModule;
|
||||
isOrderingDirty = true;
|
||||
}
|
||||
}
|
||||
if (isOrderingDirty) {
|
||||
recomputePluginOrdering();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default EventPluginRegistry;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,23 +9,20 @@ import ReactErrorUtils from 'shared/ReactErrorUtils';
|
|||
import invariant from 'fbjs/lib/invariant';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
/**
|
||||
* Injected dependencies:
|
||||
*/
|
||||
export let getFiberCurrentPropsFromNode = null;
|
||||
export let getInstanceFromNode = null;
|
||||
export let getNodeFromInstance = null;
|
||||
|
||||
/**
|
||||
* - `ComponentTree`: [required] Module that can convert between React instances
|
||||
* and actual node references.
|
||||
*/
|
||||
var ComponentTree;
|
||||
var injection = {
|
||||
export const injection = {
|
||||
injectComponentTree: function(Injected) {
|
||||
ComponentTree = Injected;
|
||||
({
|
||||
getFiberCurrentPropsFromNode,
|
||||
getInstanceFromNode,
|
||||
getNodeFromInstance,
|
||||
} = Injected);
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
Injected &&
|
||||
Injected.getNodeFromInstance &&
|
||||
Injected.getInstanceFromNode,
|
||||
getNodeFromInstance && getInstanceFromNode,
|
||||
'EventPluginUtils.injection.injectComponentTree(...): Injected ' +
|
||||
'module is missing getNodeFromInstance or getInstanceFromNode.',
|
||||
);
|
||||
|
@ -33,7 +30,7 @@ var injection = {
|
|||
},
|
||||
};
|
||||
|
||||
function isEndish(topLevelType) {
|
||||
export function isEndish(topLevelType) {
|
||||
return (
|
||||
topLevelType === 'topMouseUp' ||
|
||||
topLevelType === 'topTouchEnd' ||
|
||||
|
@ -41,10 +38,10 @@ function isEndish(topLevelType) {
|
|||
);
|
||||
}
|
||||
|
||||
function isMoveish(topLevelType) {
|
||||
export function isMoveish(topLevelType) {
|
||||
return topLevelType === 'topMouseMove' || topLevelType === 'topTouchMove';
|
||||
}
|
||||
function isStartish(topLevelType) {
|
||||
export function isStartish(topLevelType) {
|
||||
return topLevelType === 'topMouseDown' || topLevelType === 'topTouchStart';
|
||||
}
|
||||
|
||||
|
@ -80,7 +77,7 @@ if (__DEV__) {
|
|||
*/
|
||||
function executeDispatch(event, simulated, listener, inst) {
|
||||
var type = event.type || 'unknown-event';
|
||||
event.currentTarget = EventPluginUtils.getNodeFromInstance(inst);
|
||||
event.currentTarget = getNodeFromInstance(inst);
|
||||
ReactErrorUtils.invokeGuardedCallbackAndCatchFirstError(
|
||||
type,
|
||||
listener,
|
||||
|
@ -93,7 +90,7 @@ function executeDispatch(event, simulated, listener, inst) {
|
|||
/**
|
||||
* Standard/simple iteration through an event's collected dispatches.
|
||||
*/
|
||||
function executeDispatchesInOrder(event, simulated) {
|
||||
export function executeDispatchesInOrder(event, simulated) {
|
||||
var dispatchListeners = event._dispatchListeners;
|
||||
var dispatchInstances = event._dispatchInstances;
|
||||
if (__DEV__) {
|
||||
|
@ -153,7 +150,7 @@ function executeDispatchesInOrderStopAtTrueImpl(event) {
|
|||
/**
|
||||
* @see executeDispatchesInOrderStopAtTrueImpl
|
||||
*/
|
||||
function executeDispatchesInOrderStopAtTrue(event) {
|
||||
export function executeDispatchesInOrderStopAtTrue(event) {
|
||||
var ret = executeDispatchesInOrderStopAtTrueImpl(event);
|
||||
event._dispatchInstances = null;
|
||||
event._dispatchListeners = null;
|
||||
|
@ -169,7 +166,7 @@ function executeDispatchesInOrderStopAtTrue(event) {
|
|||
*
|
||||
* @return {*} The return value of executing the single dispatch.
|
||||
*/
|
||||
function executeDirectDispatch(event) {
|
||||
export function executeDirectDispatch(event) {
|
||||
if (__DEV__) {
|
||||
validateEventDispatches(event);
|
||||
}
|
||||
|
@ -180,7 +177,7 @@ function executeDirectDispatch(event) {
|
|||
'executeDirectDispatch(...): Invalid `event`.',
|
||||
);
|
||||
event.currentTarget = dispatchListener
|
||||
? EventPluginUtils.getNodeFromInstance(dispatchInstance)
|
||||
? getNodeFromInstance(dispatchInstance)
|
||||
: null;
|
||||
var res = dispatchListener ? dispatchListener(event) : null;
|
||||
event.currentTarget = null;
|
||||
|
@ -193,34 +190,6 @@ function executeDirectDispatch(event) {
|
|||
* @param {SyntheticEvent} event
|
||||
* @return {boolean} True iff number of dispatches accumulated is greater than 0.
|
||||
*/
|
||||
function hasDispatches(event) {
|
||||
export function hasDispatches(event) {
|
||||
return !!event._dispatchListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* General utilities that are useful in creating custom Event Plugins.
|
||||
*/
|
||||
var EventPluginUtils = {
|
||||
isEndish: isEndish,
|
||||
isMoveish: isMoveish,
|
||||
isStartish: isStartish,
|
||||
|
||||
executeDirectDispatch: executeDirectDispatch,
|
||||
executeDispatchesInOrder: executeDispatchesInOrder,
|
||||
executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
|
||||
hasDispatches: hasDispatches,
|
||||
|
||||
getFiberCurrentPropsFromNode: function(node) {
|
||||
return ComponentTree.getFiberCurrentPropsFromNode(node);
|
||||
},
|
||||
getInstanceFromNode: function(node) {
|
||||
return ComponentTree.getInstanceFromNode(node);
|
||||
},
|
||||
getNodeFromInstance: function(node) {
|
||||
return ComponentTree.getNodeFromInstance(node);
|
||||
},
|
||||
|
||||
injection: injection,
|
||||
};
|
||||
|
||||
export default EventPluginUtils;
|
||||
|
|
|
@ -12,14 +12,12 @@ import {
|
|||
} from 'shared/ReactTreeTraversal';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
import EventPluginHub from './EventPluginHub';
|
||||
import {getListener} from './EventPluginHub';
|
||||
import accumulateInto from './accumulateInto';
|
||||
import forEachAccumulated from './forEachAccumulated';
|
||||
|
||||
type PropagationPhases = 'bubbled' | 'captured';
|
||||
|
||||
var getListener = EventPluginHub.getListener;
|
||||
|
||||
/**
|
||||
* Some event types have a notion of different registration names for different
|
||||
* "phases" of propagation. This finds listeners by a given phase.
|
||||
|
@ -30,6 +28,16 @@ function listenerAtPhase(inst, event, propagationPhase: PropagationPhases) {
|
|||
return getListener(inst, registrationName);
|
||||
}
|
||||
|
||||
/**
|
||||
* A small set of propagation patterns, each of which will accept a small amount
|
||||
* of information, and generate a set of "dispatch ready event objects" - which
|
||||
* are sets of events that have already been annotated with a set of dispatched
|
||||
* listener functions/ids. The API is designed this way to discourage these
|
||||
* propagation strategies from actually executing the dispatches, since we
|
||||
* always want to collect the entire set of dispatches before executing even a
|
||||
* single one.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tags a `SyntheticEvent` with dispatched listeners. Creating this function
|
||||
* here, allows us to not have to bind or create functions for each event.
|
||||
|
@ -104,38 +112,18 @@ function accumulateDirectDispatchesSingle(event) {
|
|||
}
|
||||
}
|
||||
|
||||
function accumulateTwoPhaseDispatches(events) {
|
||||
export function accumulateTwoPhaseDispatches(events) {
|
||||
forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
|
||||
}
|
||||
|
||||
function accumulateTwoPhaseDispatchesSkipTarget(events) {
|
||||
export function accumulateTwoPhaseDispatchesSkipTarget(events) {
|
||||
forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget);
|
||||
}
|
||||
|
||||
function accumulateEnterLeaveDispatches(leave, enter, from, to) {
|
||||
export function accumulateEnterLeaveDispatches(leave, enter, from, to) {
|
||||
traverseEnterLeave(from, to, accumulateDispatches, leave, enter);
|
||||
}
|
||||
|
||||
function accumulateDirectDispatches(events) {
|
||||
export function accumulateDirectDispatches(events) {
|
||||
forEachAccumulated(events, accumulateDirectDispatchesSingle);
|
||||
}
|
||||
|
||||
/**
|
||||
* A small set of propagation patterns, each of which will accept a small amount
|
||||
* of information, and generate a set of "dispatch ready event objects" - which
|
||||
* are sets of events that have already been annotated with a set of dispatched
|
||||
* listener functions/ids. The API is designed this way to discourage these
|
||||
* propagation strategies from actually executing the dispatches, since we
|
||||
* always want to collect the entire set of dispatches before executing even a
|
||||
* single one.
|
||||
*
|
||||
* @constructor EventPropagators
|
||||
*/
|
||||
var EventPropagators = {
|
||||
accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches,
|
||||
accumulateTwoPhaseDispatchesSkipTarget: accumulateTwoPhaseDispatchesSkipTarget,
|
||||
accumulateDirectDispatches: accumulateDirectDispatches,
|
||||
accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches,
|
||||
};
|
||||
|
||||
export default EventPropagators;
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
|
||||
import EventPluginUtils from './EventPluginUtils';
|
||||
import {
|
||||
getInstanceFromNode,
|
||||
getFiberCurrentPropsFromNode,
|
||||
} from './EventPluginUtils';
|
||||
|
||||
// Use to restore controlled state after a change event has fired.
|
||||
|
||||
|
@ -27,7 +30,7 @@ var restoreQueue = null;
|
|||
function restoreStateOfTarget(target) {
|
||||
// We perform this translation at the end of the event loop so that we
|
||||
// always receive the correct fiber here
|
||||
var internalInstance = EventPluginUtils.getInstanceFromNode(target);
|
||||
var internalInstance = getInstanceFromNode(target);
|
||||
if (!internalInstance) {
|
||||
// Unmounted
|
||||
return;
|
||||
|
@ -38,9 +41,7 @@ function restoreStateOfTarget(target) {
|
|||
'Fiber needs to be injected to handle a fiber target for controlled ' +
|
||||
'events. This error is likely caused by a bug in React. Please file an issue.',
|
||||
);
|
||||
const props = EventPluginUtils.getFiberCurrentPropsFromNode(
|
||||
internalInstance.stateNode,
|
||||
);
|
||||
const props = getFiberCurrentPropsFromNode(internalInstance.stateNode);
|
||||
fiberHostComponent.restoreControlledState(
|
||||
internalInstance.stateNode,
|
||||
internalInstance.type,
|
||||
|
@ -48,37 +49,33 @@ function restoreStateOfTarget(target) {
|
|||
);
|
||||
}
|
||||
|
||||
var ReactControlledComponent = {
|
||||
injection: ReactControlledComponentInjection,
|
||||
export const injection = ReactControlledComponentInjection;
|
||||
|
||||
enqueueStateRestore(target) {
|
||||
if (restoreTarget) {
|
||||
if (restoreQueue) {
|
||||
restoreQueue.push(target);
|
||||
} else {
|
||||
restoreQueue = [target];
|
||||
}
|
||||
export function enqueueStateRestore(target) {
|
||||
if (restoreTarget) {
|
||||
if (restoreQueue) {
|
||||
restoreQueue.push(target);
|
||||
} else {
|
||||
restoreTarget = target;
|
||||
restoreQueue = [target];
|
||||
}
|
||||
},
|
||||
} else {
|
||||
restoreTarget = target;
|
||||
}
|
||||
}
|
||||
|
||||
restoreStateIfNeeded() {
|
||||
if (!restoreTarget) {
|
||||
return;
|
||||
export function restoreStateIfNeeded() {
|
||||
if (!restoreTarget) {
|
||||
return;
|
||||
}
|
||||
var target = restoreTarget;
|
||||
var queuedTargets = restoreQueue;
|
||||
restoreTarget = null;
|
||||
restoreQueue = null;
|
||||
|
||||
restoreStateOfTarget(target);
|
||||
if (queuedTargets) {
|
||||
for (var i = 0; i < queuedTargets.length; i++) {
|
||||
restoreStateOfTarget(queuedTargets[i]);
|
||||
}
|
||||
var target = restoreTarget;
|
||||
var queuedTargets = restoreQueue;
|
||||
restoreTarget = null;
|
||||
restoreQueue = null;
|
||||
|
||||
restoreStateOfTarget(target);
|
||||
if (queuedTargets) {
|
||||
for (var i = 0; i < queuedTargets.length; i++) {
|
||||
restoreStateOfTarget(queuedTargets[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default ReactControlledComponent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,32 +5,32 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import EventPluginHub from './EventPluginHub';
|
||||
import {
|
||||
enqueueEvents,
|
||||
processEventQueue,
|
||||
extractEvents,
|
||||
} from './EventPluginHub';
|
||||
|
||||
function runEventQueueInBatch(events) {
|
||||
EventPluginHub.enqueueEvents(events);
|
||||
EventPluginHub.processEventQueue(false);
|
||||
enqueueEvents(events);
|
||||
processEventQueue(false);
|
||||
}
|
||||
|
||||
var ReactEventEmitterMixin = {
|
||||
/**
|
||||
* Streams a fired top-level event to `EventPluginHub` where plugins have the
|
||||
* opportunity to create `ReactEvent`s to be dispatched.
|
||||
*/
|
||||
handleTopLevel: function(
|
||||
/**
|
||||
* Streams a fired top-level event to `EventPluginHub` where plugins have the
|
||||
* opportunity to create `ReactEvent`s to be dispatched.
|
||||
*/
|
||||
export function handleTopLevel(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
) {
|
||||
var events = extractEvents(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
) {
|
||||
var events = EventPluginHub.extractEvents(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
runEventQueueInBatch(events);
|
||||
},
|
||||
};
|
||||
|
||||
export default ReactEventEmitterMixin;
|
||||
);
|
||||
runEventQueueInBatch(events);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import ReactControlledComponent from './ReactControlledComponent';
|
||||
import {restoreStateIfNeeded} from './ReactControlledComponent';
|
||||
|
||||
// Used as a way to call batchedUpdates when we don't have a reference to
|
||||
// the renderer. Such as when we're dispatching events or if third party
|
||||
|
@ -18,30 +18,24 @@ var fiberBatchedUpdates = function(fn, bookkeeping) {
|
|||
return fn(bookkeeping);
|
||||
};
|
||||
|
||||
function batchedUpdates(fn, bookkeeping) {
|
||||
// If we have Fiber loaded, we need to wrap this in a batching call so that
|
||||
// Fiber can apply its default priority for this call.
|
||||
return fiberBatchedUpdates(fn, bookkeeping);
|
||||
}
|
||||
|
||||
var isNestingBatched = false;
|
||||
function batchedUpdatesWithControlledComponents(fn, bookkeeping) {
|
||||
export function batchedUpdates(fn, bookkeeping) {
|
||||
if (isNestingBatched) {
|
||||
// If we are currently inside another batch, we need to wait until it
|
||||
// fully completes before restoring state. Therefore, we add the target to
|
||||
// a queue of work.
|
||||
return batchedUpdates(fn, bookkeeping);
|
||||
return fiberBatchedUpdates(fn, bookkeeping);
|
||||
}
|
||||
isNestingBatched = true;
|
||||
try {
|
||||
return batchedUpdates(fn, bookkeeping);
|
||||
return fiberBatchedUpdates(fn, bookkeeping);
|
||||
} finally {
|
||||
// Here we wait until all updates have propagated, which is important
|
||||
// when using controlled components within layers:
|
||||
// https://github.com/facebook/react/issues/1698
|
||||
// Then we restore state of any controlled component.
|
||||
isNestingBatched = false;
|
||||
ReactControlledComponent.restoreStateIfNeeded();
|
||||
restoreStateIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,9 +45,4 @@ var ReactGenericBatchingInjection = {
|
|||
},
|
||||
};
|
||||
|
||||
var ReactGenericBatching = {
|
||||
batchedUpdates: batchedUpdatesWithControlledComponents,
|
||||
injection: ReactGenericBatchingInjection,
|
||||
};
|
||||
|
||||
export default ReactGenericBatching;
|
||||
export const injection = ReactGenericBatchingInjection;
|
||||
|
|
|
@ -7,20 +7,24 @@
|
|||
|
||||
import {getLowestCommonAncestor, isAncestor} from 'shared/ReactTreeTraversal';
|
||||
|
||||
import EventPluginUtils from './EventPluginUtils';
|
||||
import EventPropagators from './EventPropagators';
|
||||
import {
|
||||
isStartish,
|
||||
isMoveish,
|
||||
isEndish,
|
||||
executeDirectDispatch,
|
||||
hasDispatches,
|
||||
executeDispatchesInOrderStopAtTrue,
|
||||
getInstanceFromNode,
|
||||
} from './EventPluginUtils';
|
||||
import {
|
||||
accumulateDirectDispatches,
|
||||
accumulateTwoPhaseDispatches,
|
||||
accumulateTwoPhaseDispatchesSkipTarget,
|
||||
} from './EventPropagators';
|
||||
import ResponderSyntheticEvent from './ResponderSyntheticEvent';
|
||||
import ResponderTouchHistoryStore from './ResponderTouchHistoryStore';
|
||||
import accumulate from './accumulate';
|
||||
|
||||
var isStartish = EventPluginUtils.isStartish;
|
||||
var isMoveish = EventPluginUtils.isMoveish;
|
||||
var isEndish = EventPluginUtils.isEndish;
|
||||
var executeDirectDispatch = EventPluginUtils.executeDirectDispatch;
|
||||
var hasDispatches = EventPluginUtils.hasDispatches;
|
||||
var executeDispatchesInOrderStopAtTrue =
|
||||
EventPluginUtils.executeDispatchesInOrderStopAtTrue;
|
||||
|
||||
/**
|
||||
* Instance of element that should respond to touch/move types of interactions,
|
||||
* as indicated explicitly by relevant callbacks.
|
||||
|
@ -340,9 +344,9 @@ function setResponderAndExtractTransfer(
|
|||
);
|
||||
shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
|
||||
if (skipOverBubbleShouldSetFrom) {
|
||||
EventPropagators.accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent);
|
||||
accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent);
|
||||
} else {
|
||||
EventPropagators.accumulateTwoPhaseDispatches(shouldSetEvent);
|
||||
accumulateTwoPhaseDispatches(shouldSetEvent);
|
||||
}
|
||||
var wantsResponderInst = executeDispatchesInOrderStopAtTrue(shouldSetEvent);
|
||||
if (!shouldSetEvent.isPersistent()) {
|
||||
|
@ -361,7 +365,7 @@ function setResponderAndExtractTransfer(
|
|||
);
|
||||
grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
|
||||
|
||||
EventPropagators.accumulateDirectDispatches(grantEvent);
|
||||
accumulateDirectDispatches(grantEvent);
|
||||
var blockHostResponder = executeDirectDispatch(grantEvent) === true;
|
||||
if (responderInst) {
|
||||
var terminationRequestEvent = ResponderSyntheticEvent.getPooled(
|
||||
|
@ -372,7 +376,7 @@ function setResponderAndExtractTransfer(
|
|||
);
|
||||
terminationRequestEvent.touchHistory =
|
||||
ResponderTouchHistoryStore.touchHistory;
|
||||
EventPropagators.accumulateDirectDispatches(terminationRequestEvent);
|
||||
accumulateDirectDispatches(terminationRequestEvent);
|
||||
var shouldSwitch =
|
||||
!hasDispatches(terminationRequestEvent) ||
|
||||
executeDirectDispatch(terminationRequestEvent);
|
||||
|
@ -388,7 +392,7 @@ function setResponderAndExtractTransfer(
|
|||
nativeEventTarget,
|
||||
);
|
||||
terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
|
||||
EventPropagators.accumulateDirectDispatches(terminateEvent);
|
||||
accumulateDirectDispatches(terminateEvent);
|
||||
extracted = accumulate(extracted, [grantEvent, terminateEvent]);
|
||||
changeResponder(wantsResponderInst, blockHostResponder);
|
||||
} else {
|
||||
|
@ -399,7 +403,7 @@ function setResponderAndExtractTransfer(
|
|||
nativeEventTarget,
|
||||
);
|
||||
rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
|
||||
EventPropagators.accumulateDirectDispatches(rejectEvent);
|
||||
accumulateDirectDispatches(rejectEvent);
|
||||
extracted = accumulate(extracted, rejectEvent);
|
||||
}
|
||||
} else {
|
||||
|
@ -447,7 +451,7 @@ function noResponderTouches(nativeEvent) {
|
|||
var target = activeTouch.target;
|
||||
if (target !== null && target !== undefined && target !== 0) {
|
||||
// Is the original touch location inside of the current responder?
|
||||
var targetInst = EventPluginUtils.getInstanceFromNode(target);
|
||||
var targetInst = getInstanceFromNode(target);
|
||||
if (isAncestor(responderInst, targetInst)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -525,7 +529,7 @@ var ResponderEventPlugin = {
|
|||
nativeEventTarget,
|
||||
);
|
||||
gesture.touchHistory = ResponderTouchHistoryStore.touchHistory;
|
||||
EventPropagators.accumulateDirectDispatches(gesture);
|
||||
accumulateDirectDispatches(gesture);
|
||||
extracted = accumulate(extracted, gesture);
|
||||
}
|
||||
|
||||
|
@ -547,7 +551,7 @@ var ResponderEventPlugin = {
|
|||
nativeEventTarget,
|
||||
);
|
||||
finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
|
||||
EventPropagators.accumulateDirectDispatches(finalEvent);
|
||||
accumulateDirectDispatches(finalEvent);
|
||||
extracted = accumulate(extracted, finalEvent);
|
||||
changeResponder(null);
|
||||
}
|
||||
|
|
|
@ -10,9 +10,7 @@
|
|||
import invariant from 'fbjs/lib/invariant';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
import EventPluginUtils from './EventPluginUtils';
|
||||
|
||||
const {isEndish, isMoveish, isStartish} = EventPluginUtils;
|
||||
import {isEndish, isMoveish, isStartish} from './EventPluginUtils';
|
||||
|
||||
/**
|
||||
* Tracks the position and time of each active touch by `touch.identifier`. We
|
||||
|
|
|
@ -16,7 +16,7 @@ describe('EventPluginRegistry', () => {
|
|||
beforeEach(() => {
|
||||
jest.resetModuleRegistry();
|
||||
// TODO: can we express this test with only public API?
|
||||
EventPluginRegistry = require('events/EventPluginRegistry').default;
|
||||
EventPluginRegistry = require('events/EventPluginRegistry');
|
||||
|
||||
createPlugin = function(properties) {
|
||||
return Object.assign({extractEvents: function() {}}, properties);
|
||||
|
|
|
@ -58,13 +58,12 @@ describe('ReactBrowserEventEmitter', () => {
|
|||
LISTENER.mockClear();
|
||||
|
||||
// TODO: can we express this test with only public API?
|
||||
EventPluginHub = require('events/EventPluginHub').default;
|
||||
EventPluginRegistry = require('events/EventPluginRegistry').default;
|
||||
EventPluginHub = require('events/EventPluginHub');
|
||||
EventPluginRegistry = require('events/EventPluginRegistry');
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
ReactDOMComponentTree = require('../client/ReactDOMComponentTree').default;
|
||||
ReactBrowserEventEmitter = require('../events/ReactBrowserEventEmitter')
|
||||
.default;
|
||||
ReactDOMComponentTree = require('../client/ReactDOMComponentTree');
|
||||
ReactBrowserEventEmitter = require('../events/ReactBrowserEventEmitter');
|
||||
ReactTestUtils = require('react-dom/test-utils');
|
||||
TapEventPlugin = require('../events/TapEventPlugin').default;
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ describe('ReactDOMComponentTree', () => {
|
|||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
// TODO: can we express this test with only public API?
|
||||
ReactDOMComponentTree = require('../client/ReactDOMComponentTree').default;
|
||||
ReactDOMComponentTree = require('../client/ReactDOMComponentTree');
|
||||
ReactDOMServer = require('react-dom/server');
|
||||
});
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ describe('ReactDOMServer', () => {
|
|||
ReactDOMServer = require('react-dom/server');
|
||||
|
||||
// TODO: can we express this test with only public API?
|
||||
var DOMProperty = require('../shared/DOMProperty').default;
|
||||
var DOMProperty = require('../shared/DOMProperty');
|
||||
ROOT_ATTRIBUTE_NAME = DOMProperty.ROOT_ATTRIBUTE_NAME;
|
||||
});
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
var React = require('react');
|
||||
// TODO: can we express this test with only public API?
|
||||
var ReactDOMComponentTree = require('../client/ReactDOMComponentTree').default;
|
||||
var ReactDOMComponentTree = require('../client/ReactDOMComponentTree');
|
||||
var ReactTestUtils = require('react-dom/test-utils');
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,17 +5,20 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import DOMProperty from '../shared/DOMProperty';
|
||||
import {
|
||||
ATTRIBUTE_NAME_CHAR,
|
||||
ATTRIBUTE_NAME_START_CHAR,
|
||||
ID_ATTRIBUTE_NAME,
|
||||
ROOT_ATTRIBUTE_NAME,
|
||||
getPropertyInfo,
|
||||
shouldSetAttribute,
|
||||
} from '../shared/DOMProperty';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
// isAttributeNameSafe() is currently duplicated in DOMMarkupOperations.
|
||||
// TODO: Find a better place for this.
|
||||
var VALID_ATTRIBUTE_NAME_REGEX = new RegExp(
|
||||
'^[' +
|
||||
DOMProperty.ATTRIBUTE_NAME_START_CHAR +
|
||||
'][' +
|
||||
DOMProperty.ATTRIBUTE_NAME_CHAR +
|
||||
']*$',
|
||||
'^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$',
|
||||
);
|
||||
var illegalAttributeNameCache = {};
|
||||
var validatedAttributeNameCache = {};
|
||||
|
@ -54,11 +57,11 @@ function shouldIgnoreValue(propertyInfo, value) {
|
|||
*/
|
||||
|
||||
export function setAttributeForID(node, id) {
|
||||
node.setAttribute(DOMProperty.ID_ATTRIBUTE_NAME, id);
|
||||
node.setAttribute(ID_ATTRIBUTE_NAME, id);
|
||||
}
|
||||
|
||||
export function setAttributeForRoot(node) {
|
||||
node.setAttribute(DOMProperty.ROOT_ATTRIBUTE_NAME, '');
|
||||
node.setAttribute(ROOT_ATTRIBUTE_NAME, '');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,7 +71,7 @@ export function setAttributeForRoot(node) {
|
|||
*/
|
||||
export function getValueForProperty(node, name, expected) {
|
||||
if (__DEV__) {
|
||||
var propertyInfo = DOMProperty.getPropertyInfo(name);
|
||||
var propertyInfo = getPropertyInfo(name);
|
||||
if (propertyInfo) {
|
||||
var mutationMethod = propertyInfo.mutationMethod;
|
||||
if (mutationMethod || propertyInfo.mustUseProperty) {
|
||||
|
@ -151,9 +154,9 @@ export function getValueForAttribute(node, name, expected) {
|
|||
* @param {*} value
|
||||
*/
|
||||
export function setValueForProperty(node, name, value) {
|
||||
var propertyInfo = DOMProperty.getPropertyInfo(name);
|
||||
var propertyInfo = getPropertyInfo(name);
|
||||
|
||||
if (propertyInfo && DOMProperty.shouldSetAttribute(name, value)) {
|
||||
if (propertyInfo && shouldSetAttribute(name, value)) {
|
||||
var mutationMethod = propertyInfo.mutationMethod;
|
||||
if (mutationMethod) {
|
||||
mutationMethod(node, value);
|
||||
|
@ -184,7 +187,7 @@ export function setValueForProperty(node, name, value) {
|
|||
setValueForAttribute(
|
||||
node,
|
||||
name,
|
||||
DOMProperty.shouldSetAttribute(name, value) ? value : null,
|
||||
shouldSetAttribute(name, value) ? value : null,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -228,7 +231,7 @@ export function deleteValueForAttribute(node, name) {
|
|||
* @param {string} name
|
||||
*/
|
||||
export function deleteValueForProperty(node, name) {
|
||||
var propertyInfo = DOMProperty.getPropertyInfo(name);
|
||||
var propertyInfo = getPropertyInfo(name);
|
||||
if (propertyInfo) {
|
||||
var mutationMethod = propertyInfo.mutationMethod;
|
||||
if (mutationMethod) {
|
||||
|
|
|
@ -19,11 +19,11 @@ import * as ReactPortal from 'react-reconciler/src/ReactPortal';
|
|||
// TODO: direct imports like some-package/src/* are bad. Fix me.
|
||||
import {injectInternals} from 'react-reconciler/src/ReactFiberDevToolsHook';
|
||||
import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment';
|
||||
import ReactGenericBatching from 'events/ReactGenericBatching';
|
||||
import ReactControlledComponent from 'events/ReactControlledComponent';
|
||||
import EventPluginHub from 'events/EventPluginHub';
|
||||
import EventPluginRegistry from 'events/EventPluginRegistry';
|
||||
import EventPropagators from 'events/EventPropagators';
|
||||
import * as ReactGenericBatching from 'events/ReactGenericBatching';
|
||||
import * as ReactControlledComponent from 'events/ReactControlledComponent';
|
||||
import * as EventPluginHub from 'events/EventPluginHub';
|
||||
import * as EventPluginRegistry from 'events/EventPluginRegistry';
|
||||
import * as EventPropagators from 'events/EventPropagators';
|
||||
import * as ReactInstanceMap from 'shared/ReactInstanceMap';
|
||||
import ReactFeatureFlags from 'shared/ReactFeatureFlags';
|
||||
import ReactVersion from 'shared/ReactVersion';
|
||||
|
@ -34,12 +34,12 @@ import invariant from 'fbjs/lib/invariant';
|
|||
import lowPriorityWarning from 'shared/lowPriorityWarning';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
import ReactDOMComponentTree from './ReactDOMComponentTree';
|
||||
import * as ReactDOMComponentTree from './ReactDOMComponentTree';
|
||||
import * as ReactDOMFiberComponent from './ReactDOMFiberComponent';
|
||||
import * as ReactInputSelection from './ReactInputSelection';
|
||||
import validateDOMNesting from './validateDOMNesting';
|
||||
import ReactBrowserEventEmitter from '../events/ReactBrowserEventEmitter';
|
||||
import ReactDOMEventListener from '../events/ReactDOMEventListener';
|
||||
import * as ReactBrowserEventEmitter from '../events/ReactBrowserEventEmitter';
|
||||
import * as ReactDOMEventListener from '../events/ReactDOMEventListener';
|
||||
import {getChildNamespace} from '../shared/DOMNamespaces';
|
||||
import {
|
||||
ELEMENT_NODE,
|
||||
|
@ -48,9 +48,7 @@ import {
|
|||
DOCUMENT_NODE,
|
||||
DOCUMENT_FRAGMENT_NODE,
|
||||
} from '../shared/HTMLNodeType';
|
||||
import DOMProperty from '../shared/DOMProperty';
|
||||
|
||||
var {ROOT_ATTRIBUTE_NAME} = DOMProperty;
|
||||
import {ROOT_ATTRIBUTE_NAME} from '../shared/DOMProperty';
|
||||
var {
|
||||
createElement,
|
||||
createTextNode,
|
||||
|
|
|
@ -5,22 +5,20 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import EventPluginHub from 'events/EventPluginHub';
|
||||
import EventPluginUtils from 'events/EventPluginUtils';
|
||||
import * as EventPluginHub from 'events/EventPluginHub';
|
||||
import * as EventPluginUtils from 'events/EventPluginUtils';
|
||||
|
||||
import ReactDOMComponentTree from './ReactDOMComponentTree';
|
||||
import * as ReactDOMComponentTree from './ReactDOMComponentTree';
|
||||
import BeforeInputEventPlugin from '../events/BeforeInputEventPlugin';
|
||||
import ChangeEventPlugin from '../events/ChangeEventPlugin';
|
||||
import DOMEventPluginOrder from '../events/DOMEventPluginOrder';
|
||||
import EnterLeaveEventPlugin from '../events/EnterLeaveEventPlugin';
|
||||
import ReactBrowserEventEmitter from '../events/ReactBrowserEventEmitter';
|
||||
import ReactDOMEventListener from '../events/ReactDOMEventListener';
|
||||
import {handleTopLevel} from '../events/ReactBrowserEventEmitter';
|
||||
import {setHandleTopLevel} from '../events/ReactDOMEventListener';
|
||||
import SelectEventPlugin from '../events/SelectEventPlugin';
|
||||
import SimpleEventPlugin from '../events/SimpleEventPlugin';
|
||||
|
||||
ReactDOMEventListener.setHandleTopLevel(
|
||||
ReactBrowserEventEmitter.handleTopLevel,
|
||||
);
|
||||
setHandleTopLevel(handleTopLevel);
|
||||
|
||||
/**
|
||||
* Inject modules for resolving DOM hierarchy and plugin ordering.
|
||||
|
|
|
@ -12,7 +12,7 @@ var randomKey = Math.random().toString(36).slice(2);
|
|||
var internalInstanceKey = '__reactInternalInstance$' + randomKey;
|
||||
var internalEventHandlersKey = '__reactEventHandlers$' + randomKey;
|
||||
|
||||
function precacheFiberNode(hostInst, node) {
|
||||
export function precacheFiberNode(hostInst, node) {
|
||||
node[internalInstanceKey] = hostInst;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ function precacheFiberNode(hostInst, node) {
|
|||
* Given a DOM node, return the closest ReactDOMComponent or
|
||||
* ReactDOMTextComponent instance ancestor.
|
||||
*/
|
||||
function getClosestInstanceFromNode(node) {
|
||||
export function getClosestInstanceFromNode(node) {
|
||||
if (node[internalInstanceKey]) {
|
||||
return node[internalInstanceKey];
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ function getClosestInstanceFromNode(node) {
|
|||
* Given a DOM node, return the ReactDOMComponent or ReactDOMTextComponent
|
||||
* instance, or null if the node was not rendered by this React.
|
||||
*/
|
||||
function getInstanceFromNode(node) {
|
||||
export function getInstanceFromNode(node) {
|
||||
var inst = node[internalInstanceKey];
|
||||
if (inst) {
|
||||
if (inst.tag === HostComponent || inst.tag === HostText) {
|
||||
|
@ -71,7 +71,7 @@ function getInstanceFromNode(node) {
|
|||
* Given a ReactDOMComponent or ReactDOMTextComponent, return the corresponding
|
||||
* DOM node.
|
||||
*/
|
||||
function getNodeFromInstance(inst) {
|
||||
export function getNodeFromInstance(inst) {
|
||||
if (inst.tag === HostComponent || inst.tag === HostText) {
|
||||
// In Fiber this, is just the state node right now. We assume it will be
|
||||
// a host component or host text.
|
||||
|
@ -83,21 +83,10 @@ function getNodeFromInstance(inst) {
|
|||
invariant(false, 'getNodeFromInstance: Invalid argument.');
|
||||
}
|
||||
|
||||
function getFiberCurrentPropsFromNode(node) {
|
||||
export function getFiberCurrentPropsFromNode(node) {
|
||||
return node[internalEventHandlersKey] || null;
|
||||
}
|
||||
|
||||
function updateFiberProps(node, props) {
|
||||
export function updateFiberProps(node, props) {
|
||||
node[internalEventHandlersKey] = props;
|
||||
}
|
||||
|
||||
var ReactDOMComponentTree = {
|
||||
getClosestInstanceFromNode: getClosestInstanceFromNode,
|
||||
getInstanceFromNode: getInstanceFromNode,
|
||||
getNodeFromInstance: getNodeFromInstance,
|
||||
precacheFiberNode: precacheFiberNode,
|
||||
getFiberCurrentPropsFromNode,
|
||||
updateFiberProps,
|
||||
};
|
||||
|
||||
export default ReactDOMComponentTree;
|
||||
|
|
|
@ -15,8 +15,8 @@ import * as ReactFiberErrorLogger
|
|||
import ReactErrorUtils from 'shared/ReactErrorUtils';
|
||||
|
||||
import ReactDOM from './ReactDOM';
|
||||
import ReactBrowserEventEmitter from '../events/ReactBrowserEventEmitter';
|
||||
import ReactDOMComponentTree from './ReactDOMComponentTree';
|
||||
import * as ReactBrowserEventEmitter from '../events/ReactBrowserEventEmitter';
|
||||
import * as ReactDOMComponentTree from './ReactDOMComponentTree';
|
||||
import TapEventPlugin from '../events/TapEventPlugin';
|
||||
|
||||
Object.assign(
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
// TODO: direct imports like some-package/src/* are bad. Fix me.
|
||||
import ReactDebugCurrentFiber
|
||||
from 'react-reconciler/src/ReactDebugCurrentFiber';
|
||||
import EventPluginRegistry from 'events/EventPluginRegistry';
|
||||
import {registrationNameModules} from 'events/EventPluginRegistry';
|
||||
import emptyFunction from 'fbjs/lib/emptyFunction';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
|
@ -22,10 +22,10 @@ import * as ReactDOMFiberTextarea from './ReactDOMFiberTextarea';
|
|||
import * as inputValueTracking from './inputValueTracking';
|
||||
import setInnerHTML from './setInnerHTML';
|
||||
import setTextContent from './setTextContent';
|
||||
import ReactBrowserEventEmitter from '../events/ReactBrowserEventEmitter';
|
||||
import {listenTo, trapBubbledEvent} from '../events/ReactBrowserEventEmitter';
|
||||
import * as CSSPropertyOperations from '../shared/CSSPropertyOperations';
|
||||
import {Namespaces, getIntrinsicNamespace} from '../shared/DOMNamespaces';
|
||||
import DOMProperty from '../shared/DOMProperty';
|
||||
import {getPropertyInfo, shouldSetAttribute} from '../shared/DOMProperty';
|
||||
import assertValidProps from '../shared/assertValidProps';
|
||||
import {DOCUMENT_NODE, DOCUMENT_FRAGMENT_NODE} from '../shared/HTMLNodeType';
|
||||
import isCustomComponent from '../shared/isCustomComponent';
|
||||
|
@ -46,9 +46,6 @@ var {
|
|||
var didWarnInvalidHydration = false;
|
||||
var didWarnShadyDOM = false;
|
||||
|
||||
var listenTo = ReactBrowserEventEmitter.listenTo;
|
||||
var registrationNameModules = EventPluginRegistry.registrationNameModules;
|
||||
|
||||
var DANGEROUSLY_SET_INNER_HTML = 'dangerouslySetInnerHTML';
|
||||
var SUPPRESS_CONTENT_EDITABLE_WARNING = 'suppressContentEditableWarning';
|
||||
var SUPPRESS_HYDRATION_WARNING = 'suppressHydrationWarning';
|
||||
|
@ -467,7 +464,7 @@ export function setInitialProperties(
|
|||
switch (tag) {
|
||||
case 'iframe':
|
||||
case 'object':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent('topLoad', 'load', domElement);
|
||||
trapBubbledEvent('topLoad', 'load', domElement);
|
||||
props = rawProps;
|
||||
break;
|
||||
case 'video':
|
||||
|
@ -475,62 +472,34 @@ export function setInitialProperties(
|
|||
// Create listener for each media event
|
||||
for (var event in mediaEvents) {
|
||||
if (mediaEvents.hasOwnProperty(event)) {
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
event,
|
||||
mediaEvents[event],
|
||||
domElement,
|
||||
);
|
||||
trapBubbledEvent(event, mediaEvents[event], domElement);
|
||||
}
|
||||
}
|
||||
props = rawProps;
|
||||
break;
|
||||
case 'source':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topError',
|
||||
'error',
|
||||
domElement,
|
||||
);
|
||||
trapBubbledEvent('topError', 'error', domElement);
|
||||
props = rawProps;
|
||||
break;
|
||||
case 'img':
|
||||
case 'image':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topError',
|
||||
'error',
|
||||
domElement,
|
||||
);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent('topLoad', 'load', domElement);
|
||||
trapBubbledEvent('topError', 'error', domElement);
|
||||
trapBubbledEvent('topLoad', 'load', domElement);
|
||||
props = rawProps;
|
||||
break;
|
||||
case 'form':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topReset',
|
||||
'reset',
|
||||
domElement,
|
||||
);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topSubmit',
|
||||
'submit',
|
||||
domElement,
|
||||
);
|
||||
trapBubbledEvent('topReset', 'reset', domElement);
|
||||
trapBubbledEvent('topSubmit', 'submit', domElement);
|
||||
props = rawProps;
|
||||
break;
|
||||
case 'details':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topToggle',
|
||||
'toggle',
|
||||
domElement,
|
||||
);
|
||||
trapBubbledEvent('topToggle', 'toggle', domElement);
|
||||
props = rawProps;
|
||||
break;
|
||||
case 'input':
|
||||
ReactDOMFiberInput.initWrapperState(domElement, rawProps);
|
||||
props = ReactDOMFiberInput.getHostProps(domElement, rawProps);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topInvalid',
|
||||
'invalid',
|
||||
domElement,
|
||||
);
|
||||
trapBubbledEvent('topInvalid', 'invalid', domElement);
|
||||
// For controlled components we always need to ensure we're listening
|
||||
// to onChange. Even if there is no listener.
|
||||
ensureListeningTo(rootContainerElement, 'onChange');
|
||||
|
@ -542,11 +511,7 @@ export function setInitialProperties(
|
|||
case 'select':
|
||||
ReactDOMFiberSelect.initWrapperState(domElement, rawProps);
|
||||
props = ReactDOMFiberSelect.getHostProps(domElement, rawProps);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topInvalid',
|
||||
'invalid',
|
||||
domElement,
|
||||
);
|
||||
trapBubbledEvent('topInvalid', 'invalid', domElement);
|
||||
// For controlled components we always need to ensure we're listening
|
||||
// to onChange. Even if there is no listener.
|
||||
ensureListeningTo(rootContainerElement, 'onChange');
|
||||
|
@ -554,11 +519,7 @@ export function setInitialProperties(
|
|||
case 'textarea':
|
||||
ReactDOMFiberTextarea.initWrapperState(domElement, rawProps);
|
||||
props = ReactDOMFiberTextarea.getHostProps(domElement, rawProps);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topInvalid',
|
||||
'invalid',
|
||||
domElement,
|
||||
);
|
||||
trapBubbledEvent('topInvalid', 'invalid', domElement);
|
||||
// For controlled components we always need to ensure we're listening
|
||||
// to onChange. Even if there is no listener.
|
||||
ensureListeningTo(rootContainerElement, 'onChange');
|
||||
|
@ -871,63 +832,35 @@ export function diffHydratedProperties(
|
|||
switch (tag) {
|
||||
case 'iframe':
|
||||
case 'object':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent('topLoad', 'load', domElement);
|
||||
trapBubbledEvent('topLoad', 'load', domElement);
|
||||
break;
|
||||
case 'video':
|
||||
case 'audio':
|
||||
// Create listener for each media event
|
||||
for (var event in mediaEvents) {
|
||||
if (mediaEvents.hasOwnProperty(event)) {
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
event,
|
||||
mediaEvents[event],
|
||||
domElement,
|
||||
);
|
||||
trapBubbledEvent(event, mediaEvents[event], domElement);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'source':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topError',
|
||||
'error',
|
||||
domElement,
|
||||
);
|
||||
trapBubbledEvent('topError', 'error', domElement);
|
||||
break;
|
||||
case 'img':
|
||||
case 'image':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topError',
|
||||
'error',
|
||||
domElement,
|
||||
);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent('topLoad', 'load', domElement);
|
||||
trapBubbledEvent('topError', 'error', domElement);
|
||||
trapBubbledEvent('topLoad', 'load', domElement);
|
||||
break;
|
||||
case 'form':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topReset',
|
||||
'reset',
|
||||
domElement,
|
||||
);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topSubmit',
|
||||
'submit',
|
||||
domElement,
|
||||
);
|
||||
trapBubbledEvent('topReset', 'reset', domElement);
|
||||
trapBubbledEvent('topSubmit', 'submit', domElement);
|
||||
break;
|
||||
case 'details':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topToggle',
|
||||
'toggle',
|
||||
domElement,
|
||||
);
|
||||
trapBubbledEvent('topToggle', 'toggle', domElement);
|
||||
break;
|
||||
case 'input':
|
||||
ReactDOMFiberInput.initWrapperState(domElement, rawProps);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topInvalid',
|
||||
'invalid',
|
||||
domElement,
|
||||
);
|
||||
trapBubbledEvent('topInvalid', 'invalid', domElement);
|
||||
// For controlled components we always need to ensure we're listening
|
||||
// to onChange. Even if there is no listener.
|
||||
ensureListeningTo(rootContainerElement, 'onChange');
|
||||
|
@ -937,22 +870,14 @@ export function diffHydratedProperties(
|
|||
break;
|
||||
case 'select':
|
||||
ReactDOMFiberSelect.initWrapperState(domElement, rawProps);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topInvalid',
|
||||
'invalid',
|
||||
domElement,
|
||||
);
|
||||
trapBubbledEvent('topInvalid', 'invalid', domElement);
|
||||
// For controlled components we always need to ensure we're listening
|
||||
// to onChange. Even if there is no listener.
|
||||
ensureListeningTo(rootContainerElement, 'onChange');
|
||||
break;
|
||||
case 'textarea':
|
||||
ReactDOMFiberTextarea.initWrapperState(domElement, rawProps);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topInvalid',
|
||||
'invalid',
|
||||
domElement,
|
||||
);
|
||||
trapBubbledEvent('topInvalid', 'invalid', domElement);
|
||||
// For controlled components we always need to ensure we're listening
|
||||
// to onChange. Even if there is no listener.
|
||||
ensureListeningTo(rootContainerElement, 'onChange');
|
||||
|
@ -1069,8 +994,8 @@ export function diffHydratedProperties(
|
|||
if (nextProp !== serverValue) {
|
||||
warnForPropDifference(propKey, serverValue, nextProp);
|
||||
}
|
||||
} else if (DOMProperty.shouldSetAttribute(propKey, nextProp)) {
|
||||
if ((propertyInfo = DOMProperty.getPropertyInfo(propKey))) {
|
||||
} else if (shouldSetAttribute(propKey, nextProp)) {
|
||||
if ((propertyInfo = getPropertyInfo(propKey))) {
|
||||
// $FlowFixMe - Should be inferred as not undefined.
|
||||
extraAttributeNames.delete(propertyInfo.attributeName);
|
||||
serverValue = DOMPropertyOperations.getValueForProperty(
|
||||
|
|
|
@ -14,7 +14,7 @@ import invariant from 'fbjs/lib/invariant';
|
|||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
import * as DOMPropertyOperations from './DOMPropertyOperations';
|
||||
import ReactDOMComponentTree from './ReactDOMComponentTree';
|
||||
import {getFiberCurrentPropsFromNode} from './ReactDOMComponentTree';
|
||||
import ReactControlledValuePropTypes
|
||||
from '../shared/ReactControlledValuePropTypes';
|
||||
|
||||
|
@ -317,9 +317,7 @@ function updateNamedCousins(rootNode, props) {
|
|||
// and the same name are rendered into the same form (same as #1939).
|
||||
// That's probably okay; we don't support it just as we don't support
|
||||
// mixing React radio buttons with non-React ones.
|
||||
var otherProps = ReactDOMComponentTree.getFiberCurrentPropsFromNode(
|
||||
otherNode,
|
||||
);
|
||||
var otherProps = getFiberCurrentPropsFromNode(otherNode);
|
||||
invariant(
|
||||
otherProps,
|
||||
'ReactDOMInput: Mixing React and non-React radio inputs with the ' +
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
import type {TopLevelTypes} from './BrowserEventConstants';
|
||||
|
||||
import EventPropagators from 'events/EventPropagators';
|
||||
import {accumulateTwoPhaseDispatches} from 'events/EventPropagators';
|
||||
import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment';
|
||||
|
||||
import FallbackCompositionState from './FallbackCompositionState';
|
||||
import * as FallbackCompositionState from './FallbackCompositionState';
|
||||
import SyntheticCompositionEvent from './SyntheticCompositionEvent';
|
||||
import SyntheticInputEvent from './SyntheticInputEvent';
|
||||
|
||||
|
@ -263,7 +263,7 @@ function extractCompositionEvent(
|
|||
}
|
||||
}
|
||||
|
||||
EventPropagators.accumulateTwoPhaseDispatches(event);
|
||||
accumulateTwoPhaseDispatches(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
|
@ -422,7 +422,7 @@ function extractBeforeInputEvent(
|
|||
);
|
||||
|
||||
event.data = chars;
|
||||
EventPropagators.accumulateTwoPhaseDispatches(event);
|
||||
accumulateTwoPhaseDispatches(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,17 +5,17 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import EventPluginHub from 'events/EventPluginHub';
|
||||
import EventPropagators from 'events/EventPropagators';
|
||||
import ReactControlledComponent from 'events/ReactControlledComponent';
|
||||
import ReactGenericBatching from 'events/ReactGenericBatching';
|
||||
import {enqueueEvents, processEventQueue} from 'events/EventPluginHub';
|
||||
import {accumulateTwoPhaseDispatches} from 'events/EventPropagators';
|
||||
import {enqueueStateRestore} from 'events/ReactControlledComponent';
|
||||
import {batchedUpdates} from 'events/ReactGenericBatching';
|
||||
import SyntheticEvent from 'events/SyntheticEvent';
|
||||
import isTextInputElement from 'shared/isTextInputElement';
|
||||
import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment';
|
||||
|
||||
import getEventTarget from './getEventTarget';
|
||||
import isEventSupported from './isEventSupported';
|
||||
import ReactDOMComponentTree from '../client/ReactDOMComponentTree';
|
||||
import {getNodeFromInstance} from '../client/ReactDOMComponentTree';
|
||||
import * as inputValueTracking from '../client/inputValueTracking';
|
||||
|
||||
var eventTypes = {
|
||||
|
@ -46,8 +46,8 @@ function createAndAccumulateChangeEvent(inst, nativeEvent, target) {
|
|||
);
|
||||
event.type = 'change';
|
||||
// Flag this event loop as needing state restore.
|
||||
ReactControlledComponent.enqueueStateRestore(target);
|
||||
EventPropagators.accumulateTwoPhaseDispatches(event);
|
||||
enqueueStateRestore(target);
|
||||
accumulateTwoPhaseDispatches(event);
|
||||
return event;
|
||||
}
|
||||
/**
|
||||
|
@ -84,16 +84,16 @@ function manualDispatchChangeEvent(nativeEvent) {
|
|||
// components don't work properly in conjunction with event bubbling because
|
||||
// the component is rerendered and the value reverted before all the event
|
||||
// handlers can run. See https://github.com/facebook/react/issues/708.
|
||||
ReactGenericBatching.batchedUpdates(runEventInBatch, event);
|
||||
batchedUpdates(runEventInBatch, event);
|
||||
}
|
||||
|
||||
function runEventInBatch(event) {
|
||||
EventPluginHub.enqueueEvents(event);
|
||||
EventPluginHub.processEventQueue(false);
|
||||
enqueueEvents(event);
|
||||
processEventQueue(false);
|
||||
}
|
||||
|
||||
function getInstIfValueChanged(targetInst) {
|
||||
const targetNode = ReactDOMComponentTree.getNodeFromInstance(targetInst);
|
||||
const targetNode = getNodeFromInstance(targetInst);
|
||||
if (inputValueTracking.updateValueIfChanged(targetNode)) {
|
||||
return targetInst;
|
||||
}
|
||||
|
@ -262,9 +262,7 @@ var ChangeEventPlugin = {
|
|||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
) {
|
||||
var targetNode = targetInst
|
||||
? ReactDOMComponentTree.getNodeFromInstance(targetInst)
|
||||
: window;
|
||||
var targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
|
||||
|
||||
var getTargetInstFunc, handleEventFunc;
|
||||
if (shouldUseChangeEvent(targetNode)) {
|
||||
|
|
|
@ -5,10 +5,13 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import EventPropagators from 'events/EventPropagators';
|
||||
import {accumulateEnterLeaveDispatches} from 'events/EventPropagators';
|
||||
|
||||
import SyntheticMouseEvent from './SyntheticMouseEvent';
|
||||
import ReactDOMComponentTree from '../client/ReactDOMComponentTree';
|
||||
import {
|
||||
getClosestInstanceFromNode,
|
||||
getNodeFromInstance,
|
||||
} from '../client/ReactDOMComponentTree';
|
||||
|
||||
var eventTypes = {
|
||||
mouseEnter: {
|
||||
|
@ -67,9 +70,7 @@ var EnterLeaveEventPlugin = {
|
|||
if (topLevelType === 'topMouseOut') {
|
||||
from = targetInst;
|
||||
var related = nativeEvent.relatedTarget || nativeEvent.toElement;
|
||||
to = related
|
||||
? ReactDOMComponentTree.getClosestInstanceFromNode(related)
|
||||
: null;
|
||||
to = related ? getClosestInstanceFromNode(related) : null;
|
||||
} else {
|
||||
// Moving to a node from outside the window.
|
||||
from = null;
|
||||
|
@ -81,12 +82,8 @@ var EnterLeaveEventPlugin = {
|
|||
return null;
|
||||
}
|
||||
|
||||
var fromNode = from == null
|
||||
? win
|
||||
: ReactDOMComponentTree.getNodeFromInstance(from);
|
||||
var toNode = to == null
|
||||
? win
|
||||
: ReactDOMComponentTree.getNodeFromInstance(to);
|
||||
var fromNode = from == null ? win : getNodeFromInstance(from);
|
||||
var toNode = to == null ? win : getNodeFromInstance(to);
|
||||
|
||||
var leave = SyntheticMouseEvent.getPooled(
|
||||
eventTypes.mouseLeave,
|
||||
|
@ -108,7 +105,7 @@ var EnterLeaveEventPlugin = {
|
|||
enter.target = toNode;
|
||||
enter.relatedTarget = fromNode;
|
||||
|
||||
EventPropagators.accumulateEnterLeaveDispatches(leave, enter, from, to);
|
||||
accumulateEnterLeaveDispatches(leave, enter, from, to);
|
||||
|
||||
return [leave, enter];
|
||||
},
|
||||
|
|
|
@ -24,52 +24,51 @@ var compositionState = {
|
|||
_fallbackText: null,
|
||||
};
|
||||
|
||||
var FallbackCompositionState = {
|
||||
initialize(nativeEventTarget) {
|
||||
compositionState._root = nativeEventTarget;
|
||||
compositionState._startText = FallbackCompositionState.getText();
|
||||
return true;
|
||||
},
|
||||
reset() {
|
||||
compositionState._root = null;
|
||||
compositionState._startText = null;
|
||||
compositionState._fallbackText = null;
|
||||
},
|
||||
getData() {
|
||||
if (compositionState._fallbackText) {
|
||||
return compositionState._fallbackText;
|
||||
}
|
||||
export function initialize(nativeEventTarget) {
|
||||
compositionState._root = nativeEventTarget;
|
||||
compositionState._startText = getText();
|
||||
return true;
|
||||
}
|
||||
|
||||
var start;
|
||||
var startValue = compositionState._startText;
|
||||
var startLength = startValue.length;
|
||||
var end;
|
||||
var endValue = FallbackCompositionState.getText();
|
||||
var endLength = endValue.length;
|
||||
export function reset() {
|
||||
compositionState._root = null;
|
||||
compositionState._startText = null;
|
||||
compositionState._fallbackText = null;
|
||||
}
|
||||
|
||||
for (start = 0; start < startLength; start++) {
|
||||
if (startValue[start] !== endValue[start]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var minEnd = startLength - start;
|
||||
for (end = 1; end <= minEnd; end++) {
|
||||
if (startValue[startLength - end] !== endValue[endLength - end]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var sliceTail = end > 1 ? 1 - end : undefined;
|
||||
compositionState._fallbackText = endValue.slice(start, sliceTail);
|
||||
export function getData() {
|
||||
if (compositionState._fallbackText) {
|
||||
return compositionState._fallbackText;
|
||||
},
|
||||
getText() {
|
||||
if ('value' in compositionState._root) {
|
||||
return compositionState._root.value;
|
||||
}
|
||||
return compositionState._root[getTextContentAccessor()];
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default FallbackCompositionState;
|
||||
var start;
|
||||
var startValue = compositionState._startText;
|
||||
var startLength = startValue.length;
|
||||
var end;
|
||||
var endValue = getText();
|
||||
var endLength = endValue.length;
|
||||
|
||||
for (start = 0; start < startLength; start++) {
|
||||
if (startValue[start] !== endValue[start]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var minEnd = startLength - start;
|
||||
for (end = 1; end <= minEnd; end++) {
|
||||
if (startValue[startLength - end] !== endValue[endLength - end]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var sliceTail = end > 1 ? 1 - end : undefined;
|
||||
compositionState._fallbackText = endValue.slice(start, sliceTail);
|
||||
return compositionState._fallbackText;
|
||||
}
|
||||
|
||||
export function getText() {
|
||||
if ('value' in compositionState._root) {
|
||||
return compositionState._root.value;
|
||||
}
|
||||
return compositionState._root[getTextContentAccessor()];
|
||||
}
|
||||
|
|
|
@ -5,13 +5,19 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import EventPluginRegistry from 'events/EventPluginRegistry';
|
||||
import ReactEventEmitterMixin from 'events/ReactEventEmitterMixin';
|
||||
import {registrationNameDependencies} from 'events/EventPluginRegistry';
|
||||
|
||||
import ReactDOMEventListener from './ReactDOMEventListener';
|
||||
import {
|
||||
setEnabled,
|
||||
isEnabled,
|
||||
trapBubbledEvent,
|
||||
trapCapturedEvent,
|
||||
} from './ReactDOMEventListener';
|
||||
import isEventSupported from './isEventSupported';
|
||||
import BrowserEventConstants from './BrowserEventConstants';
|
||||
|
||||
export * from 'events/ReactEventEmitterMixin';
|
||||
|
||||
var {topLevelTypes} = BrowserEventConstants;
|
||||
|
||||
/**
|
||||
|
@ -88,153 +94,83 @@ function getListeningForDocument(mountAt) {
|
|||
return alreadyListeningTo[mountAt[topListenersIDKey]];
|
||||
}
|
||||
|
||||
var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
/**
|
||||
* Sets whether or not any created callbacks should be enabled.
|
||||
*
|
||||
* @param {boolean} enabled True if callbacks should be enabled.
|
||||
*/
|
||||
setEnabled: function(enabled) {
|
||||
if (ReactDOMEventListener) {
|
||||
ReactDOMEventListener.setEnabled(enabled);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* We listen for bubbled touch events on the document object.
|
||||
*
|
||||
* Firefox v8.01 (and possibly others) exhibited strange behavior when
|
||||
* mounting `onmousemove` events at some node that was not the document
|
||||
* element. The symptoms were that if your mouse is not moving over something
|
||||
* contained within that mount point (for example on the background) the
|
||||
* top-level listeners for `onmousemove` won't be called. However, if you
|
||||
* register the `mousemove` on the document object, then it will of course
|
||||
* catch all `mousemove`s. This along with iOS quirks, justifies restricting
|
||||
* top-level listeners to the document object only, at least for these
|
||||
* movement types of events and possibly all events.
|
||||
*
|
||||
* @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
|
||||
*
|
||||
* Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but
|
||||
* they bubble to document.
|
||||
*
|
||||
* @param {string} registrationName Name of listener (e.g. `onClick`).
|
||||
* @param {object} contentDocumentHandle Document which owns the container
|
||||
*/
|
||||
export function listenTo(registrationName, contentDocumentHandle) {
|
||||
var mountAt = contentDocumentHandle;
|
||||
var isListening = getListeningForDocument(mountAt);
|
||||
var dependencies = registrationNameDependencies[registrationName];
|
||||
|
||||
/**
|
||||
* @return {boolean} True if callbacks are enabled.
|
||||
*/
|
||||
isEnabled: function() {
|
||||
return !!(ReactDOMEventListener && ReactDOMEventListener.isEnabled());
|
||||
},
|
||||
|
||||
/**
|
||||
* We listen for bubbled touch events on the document object.
|
||||
*
|
||||
* Firefox v8.01 (and possibly others) exhibited strange behavior when
|
||||
* mounting `onmousemove` events at some node that was not the document
|
||||
* element. The symptoms were that if your mouse is not moving over something
|
||||
* contained within that mount point (for example on the background) the
|
||||
* top-level listeners for `onmousemove` won't be called. However, if you
|
||||
* register the `mousemove` on the document object, then it will of course
|
||||
* catch all `mousemove`s. This along with iOS quirks, justifies restricting
|
||||
* top-level listeners to the document object only, at least for these
|
||||
* movement types of events and possibly all events.
|
||||
*
|
||||
* @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
|
||||
*
|
||||
* Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but
|
||||
* they bubble to document.
|
||||
*
|
||||
* @param {string} registrationName Name of listener (e.g. `onClick`).
|
||||
* @param {object} contentDocumentHandle Document which owns the container
|
||||
*/
|
||||
listenTo: function(registrationName, contentDocumentHandle) {
|
||||
var mountAt = contentDocumentHandle;
|
||||
var isListening = getListeningForDocument(mountAt);
|
||||
var dependencies =
|
||||
EventPluginRegistry.registrationNameDependencies[registrationName];
|
||||
|
||||
for (var i = 0; i < dependencies.length; i++) {
|
||||
var dependency = dependencies[i];
|
||||
if (
|
||||
!(isListening.hasOwnProperty(dependency) && isListening[dependency])
|
||||
) {
|
||||
if (dependency === 'topWheel') {
|
||||
if (isEventSupported('wheel')) {
|
||||
ReactDOMEventListener.trapBubbledEvent(
|
||||
'topWheel',
|
||||
'wheel',
|
||||
mountAt,
|
||||
);
|
||||
} else if (isEventSupported('mousewheel')) {
|
||||
ReactDOMEventListener.trapBubbledEvent(
|
||||
'topWheel',
|
||||
'mousewheel',
|
||||
mountAt,
|
||||
);
|
||||
} else {
|
||||
// Firefox needs to capture a different mouse scroll event.
|
||||
// @see http://www.quirksmode.org/dom/events/tests/scroll.html
|
||||
ReactDOMEventListener.trapBubbledEvent(
|
||||
'topWheel',
|
||||
'DOMMouseScroll',
|
||||
mountAt,
|
||||
);
|
||||
}
|
||||
} else if (dependency === 'topScroll') {
|
||||
ReactDOMEventListener.trapCapturedEvent(
|
||||
'topScroll',
|
||||
'scroll',
|
||||
mountAt,
|
||||
);
|
||||
} else if (dependency === 'topFocus' || dependency === 'topBlur') {
|
||||
ReactDOMEventListener.trapCapturedEvent('topFocus', 'focus', mountAt);
|
||||
ReactDOMEventListener.trapCapturedEvent('topBlur', 'blur', mountAt);
|
||||
|
||||
// to make sure blur and focus event listeners are only attached once
|
||||
isListening.topBlur = true;
|
||||
isListening.topFocus = true;
|
||||
} else if (dependency === 'topCancel') {
|
||||
if (isEventSupported('cancel', true)) {
|
||||
ReactDOMEventListener.trapCapturedEvent(
|
||||
'topCancel',
|
||||
'cancel',
|
||||
mountAt,
|
||||
);
|
||||
}
|
||||
isListening.topCancel = true;
|
||||
} else if (dependency === 'topClose') {
|
||||
if (isEventSupported('close', true)) {
|
||||
ReactDOMEventListener.trapCapturedEvent(
|
||||
'topClose',
|
||||
'close',
|
||||
mountAt,
|
||||
);
|
||||
}
|
||||
isListening.topClose = true;
|
||||
} else if (topLevelTypes.hasOwnProperty(dependency)) {
|
||||
ReactDOMEventListener.trapBubbledEvent(
|
||||
dependency,
|
||||
topLevelTypes[dependency],
|
||||
mountAt,
|
||||
);
|
||||
for (var i = 0; i < dependencies.length; i++) {
|
||||
var dependency = dependencies[i];
|
||||
if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) {
|
||||
if (dependency === 'topWheel') {
|
||||
if (isEventSupported('wheel')) {
|
||||
trapBubbledEvent('topWheel', 'wheel', mountAt);
|
||||
} else if (isEventSupported('mousewheel')) {
|
||||
trapBubbledEvent('topWheel', 'mousewheel', mountAt);
|
||||
} else {
|
||||
// Firefox needs to capture a different mouse scroll event.
|
||||
// @see http://www.quirksmode.org/dom/events/tests/scroll.html
|
||||
trapBubbledEvent('topWheel', 'DOMMouseScroll', mountAt);
|
||||
}
|
||||
} else if (dependency === 'topScroll') {
|
||||
trapCapturedEvent('topScroll', 'scroll', mountAt);
|
||||
} else if (dependency === 'topFocus' || dependency === 'topBlur') {
|
||||
trapCapturedEvent('topFocus', 'focus', mountAt);
|
||||
trapCapturedEvent('topBlur', 'blur', mountAt);
|
||||
|
||||
isListening[dependency] = true;
|
||||
// to make sure blur and focus event listeners are only attached once
|
||||
isListening.topBlur = true;
|
||||
isListening.topFocus = true;
|
||||
} else if (dependency === 'topCancel') {
|
||||
if (isEventSupported('cancel', true)) {
|
||||
trapCapturedEvent('topCancel', 'cancel', mountAt);
|
||||
}
|
||||
isListening.topCancel = true;
|
||||
} else if (dependency === 'topClose') {
|
||||
if (isEventSupported('close', true)) {
|
||||
trapCapturedEvent('topClose', 'close', mountAt);
|
||||
}
|
||||
isListening.topClose = true;
|
||||
} else if (topLevelTypes.hasOwnProperty(dependency)) {
|
||||
trapBubbledEvent(dependency, topLevelTypes[dependency], mountAt);
|
||||
}
|
||||
|
||||
isListening[dependency] = true;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
isListeningToAllDependencies: function(registrationName, mountAt) {
|
||||
var isListening = getListeningForDocument(mountAt);
|
||||
var dependencies =
|
||||
EventPluginRegistry.registrationNameDependencies[registrationName];
|
||||
for (var i = 0; i < dependencies.length; i++) {
|
||||
var dependency = dependencies[i];
|
||||
if (
|
||||
!(isListening.hasOwnProperty(dependency) && isListening[dependency])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
export function isListeningToAllDependencies(registrationName, mountAt) {
|
||||
var isListening = getListeningForDocument(mountAt);
|
||||
var dependencies = registrationNameDependencies[registrationName];
|
||||
for (var i = 0; i < dependencies.length; i++) {
|
||||
var dependency = dependencies[i];
|
||||
if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
trapBubbledEvent: function(topLevelType, handlerBaseName, handle) {
|
||||
return ReactDOMEventListener.trapBubbledEvent(
|
||||
topLevelType,
|
||||
handlerBaseName,
|
||||
handle,
|
||||
);
|
||||
},
|
||||
|
||||
trapCapturedEvent: function(topLevelType, handlerBaseName, handle) {
|
||||
return ReactDOMEventListener.trapCapturedEvent(
|
||||
topLevelType,
|
||||
handlerBaseName,
|
||||
handle,
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default ReactBrowserEventEmitter;
|
||||
export {setEnabled, isEnabled, trapBubbledEvent, trapCapturedEvent};
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import ReactGenericBatching from 'events/ReactGenericBatching';
|
||||
import {batchedUpdates} from 'events/ReactGenericBatching';
|
||||
import {isFiberMounted} from 'shared/ReactFiberTreeReflection';
|
||||
import {HostRoot} from 'shared/ReactTypeOfWork';
|
||||
import EventListener from 'fbjs/lib/EventListener';
|
||||
|
||||
import getEventTarget from './getEventTarget';
|
||||
import ReactDOMComponentTree from '../client/ReactDOMComponentTree';
|
||||
import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
|
||||
|
||||
var CALLBACK_BOOKKEEPING_POOL_SIZE = 10;
|
||||
var callbackBookkeepingPool = [];
|
||||
|
@ -80,12 +80,12 @@ function handleTopLevelImpl(bookKeeping) {
|
|||
break;
|
||||
}
|
||||
bookKeeping.ancestors.push(ancestor);
|
||||
ancestor = ReactDOMComponentTree.getClosestInstanceFromNode(root);
|
||||
ancestor = getClosestInstanceFromNode(root);
|
||||
} while (ancestor);
|
||||
|
||||
for (var i = 0; i < bookKeeping.ancestors.length; i++) {
|
||||
targetInst = bookKeeping.ancestors[i];
|
||||
ReactDOMEventListener._handleTopLevel(
|
||||
_handleTopLevel(
|
||||
bookKeeping.topLevelType,
|
||||
targetInst,
|
||||
bookKeeping.nativeEvent,
|
||||
|
@ -94,99 +94,94 @@ function handleTopLevelImpl(bookKeeping) {
|
|||
}
|
||||
}
|
||||
|
||||
var ReactDOMEventListener = {
|
||||
_enabled: true,
|
||||
_handleTopLevel: null,
|
||||
// TODO: can we stop exporting these?
|
||||
export let _enabled = true;
|
||||
export let _handleTopLevel: null;
|
||||
|
||||
setHandleTopLevel: function(handleTopLevel) {
|
||||
ReactDOMEventListener._handleTopLevel = handleTopLevel;
|
||||
},
|
||||
export function setHandleTopLevel(handleTopLevel) {
|
||||
_handleTopLevel = handleTopLevel;
|
||||
}
|
||||
|
||||
setEnabled: function(enabled) {
|
||||
ReactDOMEventListener._enabled = !!enabled;
|
||||
},
|
||||
export function setEnabled(enabled) {
|
||||
_enabled = !!enabled;
|
||||
}
|
||||
|
||||
isEnabled: function() {
|
||||
return ReactDOMEventListener._enabled;
|
||||
},
|
||||
export function isEnabled() {
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traps top-level events by using event bubbling.
|
||||
*
|
||||
* @param {string} topLevelType Record from `BrowserEventConstants`.
|
||||
* @param {string} handlerBaseName Event name (e.g. "click").
|
||||
* @param {object} element Element on which to attach listener.
|
||||
* @return {?object} An object with a remove function which will forcefully
|
||||
* remove the listener.
|
||||
* @internal
|
||||
*/
|
||||
trapBubbledEvent: function(topLevelType, handlerBaseName, element) {
|
||||
if (!element) {
|
||||
return null;
|
||||
}
|
||||
return EventListener.listen(
|
||||
element,
|
||||
handlerBaseName,
|
||||
ReactDOMEventListener.dispatchEvent.bind(null, topLevelType),
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Traps top-level events by using event bubbling.
|
||||
*
|
||||
* @param {string} topLevelType Record from `BrowserEventConstants`.
|
||||
* @param {string} handlerBaseName Event name (e.g. "click").
|
||||
* @param {object} element Element on which to attach listener.
|
||||
* @return {?object} An object with a remove function which will forcefully
|
||||
* remove the listener.
|
||||
* @internal
|
||||
*/
|
||||
export function trapBubbledEvent(topLevelType, handlerBaseName, element) {
|
||||
if (!element) {
|
||||
return null;
|
||||
}
|
||||
return EventListener.listen(
|
||||
element,
|
||||
handlerBaseName,
|
||||
dispatchEvent.bind(null, topLevelType),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Traps a top-level event by using event capturing.
|
||||
*
|
||||
* @param {string} topLevelType Record from `BrowserEventConstants`.
|
||||
* @param {string} handlerBaseName Event name (e.g. "click").
|
||||
* @param {object} element Element on which to attach listener.
|
||||
* @return {?object} An object with a remove function which will forcefully
|
||||
* remove the listener.
|
||||
* @internal
|
||||
*/
|
||||
trapCapturedEvent: function(topLevelType, handlerBaseName, element) {
|
||||
if (!element) {
|
||||
return null;
|
||||
}
|
||||
return EventListener.capture(
|
||||
element,
|
||||
handlerBaseName,
|
||||
ReactDOMEventListener.dispatchEvent.bind(null, topLevelType),
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Traps a top-level event by using event capturing.
|
||||
*
|
||||
* @param {string} topLevelType Record from `BrowserEventConstants`.
|
||||
* @param {string} handlerBaseName Event name (e.g. "click").
|
||||
* @param {object} element Element on which to attach listener.
|
||||
* @return {?object} An object with a remove function which will forcefully
|
||||
* remove the listener.
|
||||
* @internal
|
||||
*/
|
||||
export function trapCapturedEvent(topLevelType, handlerBaseName, element) {
|
||||
if (!element) {
|
||||
return null;
|
||||
}
|
||||
return EventListener.capture(
|
||||
element,
|
||||
handlerBaseName,
|
||||
dispatchEvent.bind(null, topLevelType),
|
||||
);
|
||||
}
|
||||
|
||||
dispatchEvent: function(topLevelType, nativeEvent) {
|
||||
if (!ReactDOMEventListener._enabled) {
|
||||
return;
|
||||
}
|
||||
export function dispatchEvent(topLevelType, nativeEvent) {
|
||||
if (!_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
var nativeEventTarget = getEventTarget(nativeEvent);
|
||||
var targetInst = ReactDOMComponentTree.getClosestInstanceFromNode(
|
||||
nativeEventTarget,
|
||||
);
|
||||
if (
|
||||
targetInst !== null &&
|
||||
typeof targetInst.tag === 'number' &&
|
||||
!isFiberMounted(targetInst)
|
||||
) {
|
||||
// If we get an event (ex: img onload) before committing that
|
||||
// component's mount, ignore it for now (that is, treat it as if it was an
|
||||
// event on a non-React tree). We might also consider queueing events and
|
||||
// dispatching them after the mount.
|
||||
targetInst = null;
|
||||
}
|
||||
var nativeEventTarget = getEventTarget(nativeEvent);
|
||||
var targetInst = getClosestInstanceFromNode(nativeEventTarget);
|
||||
if (
|
||||
targetInst !== null &&
|
||||
typeof targetInst.tag === 'number' &&
|
||||
!isFiberMounted(targetInst)
|
||||
) {
|
||||
// If we get an event (ex: img onload) before committing that
|
||||
// component's mount, ignore it for now (that is, treat it as if it was an
|
||||
// event on a non-React tree). We might also consider queueing events and
|
||||
// dispatching them after the mount.
|
||||
targetInst = null;
|
||||
}
|
||||
|
||||
var bookKeeping = getTopLevelCallbackBookKeeping(
|
||||
topLevelType,
|
||||
nativeEvent,
|
||||
targetInst,
|
||||
);
|
||||
var bookKeeping = getTopLevelCallbackBookKeeping(
|
||||
topLevelType,
|
||||
nativeEvent,
|
||||
targetInst,
|
||||
);
|
||||
|
||||
try {
|
||||
// Event queue being processed in the same cycle allows
|
||||
// `preventDefault`.
|
||||
ReactGenericBatching.batchedUpdates(handleTopLevelImpl, bookKeeping);
|
||||
} finally {
|
||||
releaseTopLevelCallbackBookKeeping(bookKeeping);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default ReactDOMEventListener;
|
||||
try {
|
||||
// Event queue being processed in the same cycle allows
|
||||
// `preventDefault`.
|
||||
batchedUpdates(handleTopLevelImpl, bookKeeping);
|
||||
} finally {
|
||||
releaseTopLevelCallbackBookKeeping(bookKeeping);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,15 +5,15 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import EventPropagators from 'events/EventPropagators';
|
||||
import {accumulateTwoPhaseDispatches} from 'events/EventPropagators';
|
||||
import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment';
|
||||
import SyntheticEvent from 'events/SyntheticEvent';
|
||||
import isTextInputElement from 'shared/isTextInputElement';
|
||||
import getActiveElement from 'fbjs/lib/getActiveElement';
|
||||
import shallowEqual from 'fbjs/lib/shallowEqual';
|
||||
|
||||
import ReactBrowserEventEmitter from './ReactBrowserEventEmitter';
|
||||
import ReactDOMComponentTree from '../client/ReactDOMComponentTree';
|
||||
import {isListeningToAllDependencies} from './ReactBrowserEventEmitter';
|
||||
import {getNodeFromInstance} from '../client/ReactDOMComponentTree';
|
||||
import * as ReactInputSelection from '../client/ReactInputSelection';
|
||||
import {DOCUMENT_NODE} from '../shared/HTMLNodeType';
|
||||
|
||||
|
@ -46,11 +46,6 @@ var activeElementInst = null;
|
|||
var lastSelection = null;
|
||||
var mouseDown = false;
|
||||
|
||||
// Track whether all listeners exists for this plugin. If none exist, we do
|
||||
// not extract events. See #3639.
|
||||
var isListeningToAllDependencies =
|
||||
ReactBrowserEventEmitter.isListeningToAllDependencies;
|
||||
|
||||
/**
|
||||
* Get an object which is a unique representation of the current selection.
|
||||
*
|
||||
|
@ -114,7 +109,7 @@ function constructSelectEvent(nativeEvent, nativeEventTarget) {
|
|||
syntheticEvent.type = 'select';
|
||||
syntheticEvent.target = activeElement;
|
||||
|
||||
EventPropagators.accumulateTwoPhaseDispatches(syntheticEvent);
|
||||
accumulateTwoPhaseDispatches(syntheticEvent);
|
||||
|
||||
return syntheticEvent;
|
||||
}
|
||||
|
@ -150,13 +145,13 @@ var SelectEventPlugin = {
|
|||
: nativeEventTarget.nodeType === DOCUMENT_NODE
|
||||
? nativeEventTarget
|
||||
: nativeEventTarget.ownerDocument;
|
||||
// Track whether all listeners exists for this plugin. If none exist, we do
|
||||
// not extract events. See #3639.
|
||||
if (!doc || !isListeningToAllDependencies('onSelect', doc)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var targetNode = targetInst
|
||||
? ReactDOMComponentTree.getNodeFromInstance(targetInst)
|
||||
: window;
|
||||
var targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
|
||||
|
||||
switch (topLevelType) {
|
||||
// Track the input node that has focus.
|
||||
|
|
|
@ -15,7 +15,7 @@ import type {
|
|||
import type {Fiber} from 'react-reconciler/src/ReactFiber';
|
||||
import type {EventTypes, PluginModule} from 'events/PluginModuleType';
|
||||
|
||||
import EventPropagators from 'events/EventPropagators';
|
||||
import {accumulateTwoPhaseDispatches} from 'events/EventPropagators';
|
||||
import SyntheticEvent from 'events/SyntheticEvent';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
|
@ -274,7 +274,7 @@ var SimpleEventPlugin: PluginModule<MouseEvent> = {
|
|||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
);
|
||||
EventPropagators.accumulateTwoPhaseDispatches(event);
|
||||
accumulateTwoPhaseDispatches(event);
|
||||
return event;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -7,15 +7,12 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import EventPluginUtils from 'events/EventPluginUtils';
|
||||
import EventPropagators from 'events/EventPropagators';
|
||||
import {isStartish, isEndish} from 'events/EventPluginUtils';
|
||||
import {accumulateTwoPhaseDispatches} from 'events/EventPropagators';
|
||||
import TouchEventUtils from 'fbjs/lib/TouchEventUtils';
|
||||
|
||||
import SyntheticUIEvent from './SyntheticUIEvent';
|
||||
|
||||
var isStartish = EventPluginUtils.isStartish;
|
||||
var isEndish = EventPluginUtils.isEndish;
|
||||
|
||||
/**
|
||||
* We are extending the Flow 'Touch' declaration to enable using bracket
|
||||
* notation to access properties.
|
||||
|
@ -144,7 +141,7 @@ var TapEventPlugin = {
|
|||
startCoords.x = 0;
|
||||
startCoords.y = 0;
|
||||
}
|
||||
EventPropagators.accumulateTwoPhaseDispatches(event);
|
||||
accumulateTwoPhaseDispatches(event);
|
||||
return event;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -49,7 +49,7 @@ describe('BeforeInputEventPlugin', function() {
|
|||
this.ReactDOM = require('react-dom');
|
||||
|
||||
// TODO: can we express this test with only public API?
|
||||
this.ReactDOMComponentTree = require('../../client/ReactDOMComponentTree').default;
|
||||
this.ReactDOMComponentTree = require('../../client/ReactDOMComponentTree');
|
||||
this.SyntheticCompositionEvent = require('../SyntheticCompositionEvent').default;
|
||||
this.SyntheticInputEvent = require('../SyntheticInputEvent').default;
|
||||
this.BeforeInputEventPlugin = require('../BeforeInputEventPlugin').default;
|
||||
|
|
|
@ -16,7 +16,7 @@ describe('FallbackCompositionState', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
// TODO: can we express this test with only public API?
|
||||
FallbackCompositionState = require('../FallbackCompositionState').default;
|
||||
FallbackCompositionState = require('../FallbackCompositionState');
|
||||
});
|
||||
|
||||
function getInput() {
|
||||
|
|
|
@ -30,8 +30,7 @@ describe('SelectEventPlugin', () => {
|
|||
ReactDOM = require('react-dom');
|
||||
ReactTestUtils = require('react-dom/test-utils');
|
||||
// TODO: can we express this test with only public API?
|
||||
ReactDOMComponentTree = require('../../client/ReactDOMComponentTree')
|
||||
.default;
|
||||
ReactDOMComponentTree = require('../../client/ReactDOMComponentTree');
|
||||
SelectEventPlugin = require('../SelectEventPlugin').default;
|
||||
});
|
||||
|
||||
|
|
|
@ -5,7 +5,15 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import DOMProperty from '../shared/DOMProperty';
|
||||
import {
|
||||
ATTRIBUTE_NAME_CHAR,
|
||||
ATTRIBUTE_NAME_START_CHAR,
|
||||
ID_ATTRIBUTE_NAME,
|
||||
ROOT_ATTRIBUTE_NAME,
|
||||
getPropertyInfo,
|
||||
shouldAttributeAcceptBooleanValue,
|
||||
shouldSetAttribute,
|
||||
} from '../shared/DOMProperty';
|
||||
import quoteAttributeValueForBrowser
|
||||
from '../shared/quoteAttributeValueForBrowser';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
@ -13,11 +21,7 @@ import warning from 'fbjs/lib/warning';
|
|||
// isAttributeNameSafe() is currently duplicated in DOMPropertyOperations.
|
||||
// TODO: Find a better place for this.
|
||||
var VALID_ATTRIBUTE_NAME_REGEX = new RegExp(
|
||||
'^[' +
|
||||
DOMProperty.ATTRIBUTE_NAME_START_CHAR +
|
||||
'][' +
|
||||
DOMProperty.ATTRIBUTE_NAME_CHAR +
|
||||
']*$',
|
||||
'^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$',
|
||||
);
|
||||
var illegalAttributeNameCache = {};
|
||||
var validatedAttributeNameCache = {};
|
||||
|
@ -54,70 +58,65 @@ function shouldIgnoreValue(propertyInfo, value) {
|
|||
/**
|
||||
* Operations for dealing with DOM properties.
|
||||
*/
|
||||
var DOMMarkupOperations = {
|
||||
/**
|
||||
* Creates markup for the ID property.
|
||||
*
|
||||
* @param {string} id Unescaped ID.
|
||||
* @return {string} Markup string.
|
||||
*/
|
||||
createMarkupForID: function(id) {
|
||||
return (
|
||||
DOMProperty.ID_ATTRIBUTE_NAME + '=' + quoteAttributeValueForBrowser(id)
|
||||
);
|
||||
},
|
||||
|
||||
createMarkupForRoot: function() {
|
||||
return DOMProperty.ROOT_ATTRIBUTE_NAME + '=""';
|
||||
},
|
||||
/**
|
||||
* Creates markup for the ID property.
|
||||
*
|
||||
* @param {string} id Unescaped ID.
|
||||
* @return {string} Markup string.
|
||||
*/
|
||||
export function createMarkupForID(id) {
|
||||
return ID_ATTRIBUTE_NAME + '=' + quoteAttributeValueForBrowser(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates markup for a property.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {*} value
|
||||
* @return {?string} Markup string, or null if the property was invalid.
|
||||
*/
|
||||
createMarkupForProperty: function(name, value) {
|
||||
var propertyInfo = DOMProperty.getPropertyInfo(name);
|
||||
if (propertyInfo) {
|
||||
if (shouldIgnoreValue(propertyInfo, value)) {
|
||||
return '';
|
||||
}
|
||||
var attributeName = propertyInfo.attributeName;
|
||||
if (
|
||||
propertyInfo.hasBooleanValue ||
|
||||
(propertyInfo.hasOverloadedBooleanValue && value === true)
|
||||
) {
|
||||
return attributeName + '=""';
|
||||
} else if (
|
||||
typeof value !== 'boolean' ||
|
||||
DOMProperty.shouldAttributeAcceptBooleanValue(name)
|
||||
) {
|
||||
return attributeName + '=' + quoteAttributeValueForBrowser(value);
|
||||
}
|
||||
} else if (DOMProperty.shouldSetAttribute(name, value)) {
|
||||
if (value == null) {
|
||||
return '';
|
||||
}
|
||||
return name + '=' + quoteAttributeValueForBrowser(value);
|
||||
export function createMarkupForRoot() {
|
||||
return ROOT_ATTRIBUTE_NAME + '=""';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates markup for a property.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {*} value
|
||||
* @return {?string} Markup string, or null if the property was invalid.
|
||||
*/
|
||||
export function createMarkupForProperty(name, value) {
|
||||
var propertyInfo = getPropertyInfo(name);
|
||||
if (propertyInfo) {
|
||||
if (shouldIgnoreValue(propertyInfo, value)) {
|
||||
return '';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates markup for a custom property.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {*} value
|
||||
* @return {string} Markup string, or empty string if the property was invalid.
|
||||
*/
|
||||
createMarkupForCustomAttribute: function(name, value) {
|
||||
if (!isAttributeNameSafe(name) || value == null) {
|
||||
var attributeName = propertyInfo.attributeName;
|
||||
if (
|
||||
propertyInfo.hasBooleanValue ||
|
||||
(propertyInfo.hasOverloadedBooleanValue && value === true)
|
||||
) {
|
||||
return attributeName + '=""';
|
||||
} else if (
|
||||
typeof value !== 'boolean' ||
|
||||
shouldAttributeAcceptBooleanValue(name)
|
||||
) {
|
||||
return attributeName + '=' + quoteAttributeValueForBrowser(value);
|
||||
}
|
||||
} else if (shouldSetAttribute(name, value)) {
|
||||
if (value == null) {
|
||||
return '';
|
||||
}
|
||||
return name + '=' + quoteAttributeValueForBrowser(value);
|
||||
},
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export default DOMMarkupOperations;
|
||||
/**
|
||||
* Creates markup for a custom property.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {*} value
|
||||
* @return {string} Markup string, or empty string if the property was invalid.
|
||||
*/
|
||||
export function createMarkupForCustomAttribute(name, value) {
|
||||
if (!isAttributeNameSafe(name) || value == null) {
|
||||
return '';
|
||||
}
|
||||
return name + '=' + quoteAttributeValueForBrowser(value);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,11 @@ import checkPropTypes from 'prop-types/checkPropTypes';
|
|||
import describeComponentFrame from 'shared/describeComponentFrame';
|
||||
import {ReactDebugCurrentFrame} from 'shared/ReactGlobalSharedState';
|
||||
|
||||
import DOMMarkupOperations from './DOMMarkupOperations';
|
||||
import {
|
||||
createMarkupForCustomAttribute,
|
||||
createMarkupForProperty,
|
||||
createMarkupForRoot,
|
||||
} from './DOMMarkupOperations';
|
||||
import {
|
||||
Namespaces,
|
||||
getIntrinsicNamespace,
|
||||
|
@ -319,13 +323,10 @@ function createOpenTagMarkup(
|
|||
var markup = null;
|
||||
if (isCustomComponent(tagLowercase, props)) {
|
||||
if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
|
||||
markup = DOMMarkupOperations.createMarkupForCustomAttribute(
|
||||
propKey,
|
||||
propValue,
|
||||
);
|
||||
markup = createMarkupForCustomAttribute(propKey, propValue);
|
||||
}
|
||||
} else {
|
||||
markup = DOMMarkupOperations.createMarkupForProperty(propKey, propValue);
|
||||
markup = createMarkupForProperty(propKey, propValue);
|
||||
}
|
||||
if (markup) {
|
||||
ret += ' ' + markup;
|
||||
|
@ -339,7 +340,7 @@ function createOpenTagMarkup(
|
|||
}
|
||||
|
||||
if (isRootElement) {
|
||||
ret += ' ' + DOMMarkupOperations.createMarkupForRoot();
|
||||
ret += ' ' + createMarkupForRoot();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ var DOMPropertyInjection = {
|
|||
|
||||
for (var propName in Properties) {
|
||||
invariant(
|
||||
!DOMProperty.properties.hasOwnProperty(propName),
|
||||
!properties.hasOwnProperty(propName),
|
||||
"injectDOMPropertyConfig(...): You're trying to inject DOM property " +
|
||||
"'%s' which has already been injected. You may be accidentally " +
|
||||
'injecting the same DOM property config twice, or you may be ' +
|
||||
|
@ -129,135 +129,114 @@ var DOMPropertyInjection = {
|
|||
// without case-sensitivity. This allows the whitelist to pick up
|
||||
// `allowfullscreen`, which should be written using the property configuration
|
||||
// for `allowFullscreen`
|
||||
DOMProperty.properties[propName] = propertyInfo;
|
||||
properties[propName] = propertyInfo;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/* eslint-disable max-len */
|
||||
var ATTRIBUTE_NAME_START_CHAR =
|
||||
export const ATTRIBUTE_NAME_START_CHAR =
|
||||
':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD';
|
||||
/* eslint-enable max-len */
|
||||
export const ATTRIBUTE_NAME_CHAR =
|
||||
ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040';
|
||||
|
||||
export const ID_ATTRIBUTE_NAME = 'data-reactid';
|
||||
export const ROOT_ATTRIBUTE_NAME = 'data-reactroot';
|
||||
|
||||
/**
|
||||
* DOMProperty exports lookup objects that can be used like functions:
|
||||
* Map from property "standard name" to an object with info about how to set
|
||||
* the property in the DOM. Each object contains:
|
||||
*
|
||||
* > DOMProperty.isValid['id']
|
||||
* true
|
||||
* > DOMProperty.isValid['foobar']
|
||||
* undefined
|
||||
*
|
||||
* Although this may be confusing, it performs better in general.
|
||||
*
|
||||
* @see http://jsperf.com/key-exists
|
||||
* @see http://jsperf.com/key-missing
|
||||
* attributeName:
|
||||
* Used when rendering markup or with `*Attribute()`.
|
||||
* attributeNamespace
|
||||
* propertyName:
|
||||
* Used on DOM node instances. (This includes properties that mutate due to
|
||||
* external factors.)
|
||||
* mutationMethod:
|
||||
* If non-null, used instead of the property or `setAttribute()` after
|
||||
* initial render.
|
||||
* mustUseProperty:
|
||||
* Whether the property must be accessed and mutated as an object property.
|
||||
* hasBooleanValue:
|
||||
* Whether the property should be removed when set to a falsey value.
|
||||
* hasNumericValue:
|
||||
* Whether the property must be numeric or parse as a numeric and should be
|
||||
* removed when set to a falsey value.
|
||||
* hasPositiveNumericValue:
|
||||
* Whether the property must be positive numeric or parse as a positive
|
||||
* numeric and should be removed when set to a falsey value.
|
||||
* hasOverloadedBooleanValue:
|
||||
* Whether the property can be used as a flag as well as with a value.
|
||||
* Removed when strictly equal to false; present without a value when
|
||||
* strictly equal to true; present with a value otherwise.
|
||||
*/
|
||||
var DOMProperty = {
|
||||
ID_ATTRIBUTE_NAME: 'data-reactid',
|
||||
ROOT_ATTRIBUTE_NAME: 'data-reactroot',
|
||||
export const properties = {};
|
||||
|
||||
ATTRIBUTE_NAME_START_CHAR: ATTRIBUTE_NAME_START_CHAR,
|
||||
ATTRIBUTE_NAME_CHAR: ATTRIBUTE_NAME_START_CHAR +
|
||||
'\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040',
|
||||
|
||||
/**
|
||||
* Map from property "standard name" to an object with info about how to set
|
||||
* the property in the DOM. Each object contains:
|
||||
*
|
||||
* attributeName:
|
||||
* Used when rendering markup or with `*Attribute()`.
|
||||
* attributeNamespace
|
||||
* propertyName:
|
||||
* Used on DOM node instances. (This includes properties that mutate due to
|
||||
* external factors.)
|
||||
* mutationMethod:
|
||||
* If non-null, used instead of the property or `setAttribute()` after
|
||||
* initial render.
|
||||
* mustUseProperty:
|
||||
* Whether the property must be accessed and mutated as an object property.
|
||||
* hasBooleanValue:
|
||||
* Whether the property should be removed when set to a falsey value.
|
||||
* hasNumericValue:
|
||||
* Whether the property must be numeric or parse as a numeric and should be
|
||||
* removed when set to a falsey value.
|
||||
* hasPositiveNumericValue:
|
||||
* Whether the property must be positive numeric or parse as a positive
|
||||
* numeric and should be removed when set to a falsey value.
|
||||
* hasOverloadedBooleanValue:
|
||||
* Whether the property can be used as a flag as well as with a value.
|
||||
* Removed when strictly equal to false; present without a value when
|
||||
* strictly equal to true; present with a value otherwise.
|
||||
*/
|
||||
properties: {},
|
||||
|
||||
/**
|
||||
* Checks whether a property name is a writeable attribute.
|
||||
* @method
|
||||
*/
|
||||
shouldSetAttribute: function(name, value) {
|
||||
if (DOMProperty.isReservedProp(name)) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
(name[0] === 'o' || name[0] === 'O') &&
|
||||
(name[1] === 'n' || name[1] === 'N') &&
|
||||
name.length > 2
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (value === null) {
|
||||
/**
|
||||
* Checks whether a property name is a writeable attribute.
|
||||
* @method
|
||||
*/
|
||||
export function shouldSetAttribute(name, value) {
|
||||
if (isReservedProp(name)) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
(name[0] === 'o' || name[0] === 'O') &&
|
||||
(name[1] === 'n' || name[1] === 'N') &&
|
||||
name.length > 2
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (value === null) {
|
||||
return true;
|
||||
}
|
||||
switch (typeof value) {
|
||||
case 'boolean':
|
||||
return shouldAttributeAcceptBooleanValue(name);
|
||||
case 'undefined':
|
||||
case 'number':
|
||||
case 'string':
|
||||
case 'object':
|
||||
return true;
|
||||
}
|
||||
switch (typeof value) {
|
||||
case 'boolean':
|
||||
return DOMProperty.shouldAttributeAcceptBooleanValue(name);
|
||||
case 'undefined':
|
||||
case 'number':
|
||||
case 'string':
|
||||
case 'object':
|
||||
return true;
|
||||
default:
|
||||
// function, symbol
|
||||
return false;
|
||||
}
|
||||
},
|
||||
default:
|
||||
// function, symbol
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
getPropertyInfo(name) {
|
||||
return DOMProperty.properties.hasOwnProperty(name)
|
||||
? DOMProperty.properties[name]
|
||||
: null;
|
||||
},
|
||||
export function getPropertyInfo(name) {
|
||||
return properties.hasOwnProperty(name) ? properties[name] : null;
|
||||
}
|
||||
|
||||
shouldAttributeAcceptBooleanValue(name) {
|
||||
if (DOMProperty.isReservedProp(name)) {
|
||||
return true;
|
||||
}
|
||||
let propertyInfo = DOMProperty.getPropertyInfo(name);
|
||||
if (propertyInfo) {
|
||||
return (
|
||||
propertyInfo.hasBooleanValue ||
|
||||
propertyInfo.hasStringBooleanValue ||
|
||||
propertyInfo.hasOverloadedBooleanValue
|
||||
);
|
||||
}
|
||||
var prefix = name.toLowerCase().slice(0, 5);
|
||||
return prefix === 'data-' || prefix === 'aria-';
|
||||
},
|
||||
export function shouldAttributeAcceptBooleanValue(name) {
|
||||
if (isReservedProp(name)) {
|
||||
return true;
|
||||
}
|
||||
let propertyInfo = getPropertyInfo(name);
|
||||
if (propertyInfo) {
|
||||
return (
|
||||
propertyInfo.hasBooleanValue ||
|
||||
propertyInfo.hasStringBooleanValue ||
|
||||
propertyInfo.hasOverloadedBooleanValue
|
||||
);
|
||||
}
|
||||
var prefix = name.toLowerCase().slice(0, 5);
|
||||
return prefix === 'data-' || prefix === 'aria-';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a property name is within the list of properties
|
||||
* reserved for internal React operations. These properties should
|
||||
* not be set on an HTML element.
|
||||
*
|
||||
* @private
|
||||
* @param {string} name
|
||||
* @return {boolean} If the name is within reserved props
|
||||
*/
|
||||
isReservedProp(name) {
|
||||
return RESERVED_PROPS.hasOwnProperty(name);
|
||||
},
|
||||
/**
|
||||
* Checks to see if a property name is within the list of properties
|
||||
* reserved for internal React operations. These properties should
|
||||
* not be set on an HTML element.
|
||||
*
|
||||
* @private
|
||||
* @param {string} name
|
||||
* @return {boolean} If the name is within reserved props
|
||||
*/
|
||||
export function isReservedProp(name) {
|
||||
return RESERVED_PROPS.hasOwnProperty(name);
|
||||
}
|
||||
|
||||
injection: DOMPropertyInjection,
|
||||
};
|
||||
|
||||
export default DOMProperty;
|
||||
export const injection = DOMPropertyInjection;
|
||||
|
|
|
@ -5,16 +5,14 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import DOMProperty from './DOMProperty';
|
||||
import {injection} from './DOMProperty';
|
||||
|
||||
var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
|
||||
var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
|
||||
var HAS_NUMERIC_VALUE = DOMProperty.injection.HAS_NUMERIC_VALUE;
|
||||
var HAS_POSITIVE_NUMERIC_VALUE =
|
||||
DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE;
|
||||
var HAS_OVERLOADED_BOOLEAN_VALUE =
|
||||
DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE;
|
||||
var HAS_STRING_BOOLEAN_VALUE = DOMProperty.injection.HAS_STRING_BOOLEAN_VALUE;
|
||||
var MUST_USE_PROPERTY = injection.MUST_USE_PROPERTY;
|
||||
var HAS_BOOLEAN_VALUE = injection.HAS_BOOLEAN_VALUE;
|
||||
var HAS_NUMERIC_VALUE = injection.HAS_NUMERIC_VALUE;
|
||||
var HAS_POSITIVE_NUMERIC_VALUE = injection.HAS_POSITIVE_NUMERIC_VALUE;
|
||||
var HAS_OVERLOADED_BOOLEAN_VALUE = injection.HAS_OVERLOADED_BOOLEAN_VALUE;
|
||||
var HAS_STRING_BOOLEAN_VALUE = injection.HAS_STRING_BOOLEAN_VALUE;
|
||||
|
||||
var HTMLDOMPropertyConfig = {
|
||||
// When adding attributes to this list, be sure to also add them to
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import DOMProperty from './DOMProperty';
|
||||
import * as DOMProperty from './DOMProperty';
|
||||
import HTMLDOMPropertyConfig from './HTMLDOMPropertyConfig';
|
||||
import SVGDOMPropertyConfig from './SVGDOMPropertyConfig';
|
||||
|
||||
|
|
|
@ -8,15 +8,13 @@
|
|||
import warning from 'fbjs/lib/warning';
|
||||
import {ReactDebugCurrentFrame} from 'shared/ReactGlobalSharedState';
|
||||
|
||||
import DOMProperty from './DOMProperty';
|
||||
import {ATTRIBUTE_NAME_CHAR} from './DOMProperty';
|
||||
import isCustomComponent from './isCustomComponent';
|
||||
import validAriaProperties from './validAriaProperties';
|
||||
|
||||
var warnedProperties = {};
|
||||
var rARIA = new RegExp('^(aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$');
|
||||
var rARIACamel = new RegExp(
|
||||
'^(aria)[A-Z][' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$',
|
||||
);
|
||||
var rARIA = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$');
|
||||
var rARIACamel = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$');
|
||||
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
|
|
|
@ -5,11 +5,20 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import EventPluginRegistry from 'events/EventPluginRegistry';
|
||||
import {
|
||||
registrationNameModules,
|
||||
plugins,
|
||||
possibleRegistrationNames,
|
||||
} from 'events/EventPluginRegistry';
|
||||
import {ReactDebugCurrentFrame} from 'shared/ReactGlobalSharedState';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
import DOMProperty from './DOMProperty';
|
||||
import {
|
||||
ATTRIBUTE_NAME_CHAR,
|
||||
isReservedProp,
|
||||
shouldAttributeAcceptBooleanValue,
|
||||
shouldSetAttribute,
|
||||
} from './DOMProperty';
|
||||
import isCustomComponent from './isCustomComponent';
|
||||
import possibleStandardNames from './possibleStandardNames';
|
||||
|
||||
|
@ -22,34 +31,29 @@ if (__DEV__) {
|
|||
var warnedProperties = {};
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
var EVENT_NAME_REGEX = /^on[A-Z]/;
|
||||
var rARIA = new RegExp('^(aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$');
|
||||
var rARIACamel = new RegExp(
|
||||
'^(aria)[A-Z][' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$',
|
||||
);
|
||||
var rARIA = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$');
|
||||
var rARIACamel = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$');
|
||||
|
||||
var validateProperty = function(tagName, name, value) {
|
||||
if (hasOwnProperty.call(warnedProperties, name) && warnedProperties[name]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (EventPluginRegistry.registrationNameModules.hasOwnProperty(name)) {
|
||||
if (registrationNameModules.hasOwnProperty(name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
EventPluginRegistry.plugins.length === 0 &&
|
||||
EVENT_NAME_REGEX.test(name)
|
||||
) {
|
||||
if (plugins.length === 0 && EVENT_NAME_REGEX.test(name)) {
|
||||
// If no event plugins have been injected, we might be in a server environment.
|
||||
// Don't check events in this case.
|
||||
return true;
|
||||
}
|
||||
|
||||
var lowerCasedName = name.toLowerCase();
|
||||
var registrationName = EventPluginRegistry.possibleRegistrationNames.hasOwnProperty(
|
||||
var registrationName = possibleRegistrationNames.hasOwnProperty(
|
||||
lowerCasedName,
|
||||
)
|
||||
? EventPluginRegistry.possibleRegistrationNames[lowerCasedName]
|
||||
? possibleRegistrationNames[lowerCasedName]
|
||||
: null;
|
||||
|
||||
if (registrationName != null) {
|
||||
|
@ -140,7 +144,7 @@ if (__DEV__) {
|
|||
return true;
|
||||
}
|
||||
|
||||
const isReserved = DOMProperty.isReservedProp(name);
|
||||
const isReserved = isReservedProp(name);
|
||||
|
||||
// Known attributes should match the casing specified in the property config.
|
||||
if (possibleStandardNames.hasOwnProperty(lowerCasedName)) {
|
||||
|
@ -176,7 +180,7 @@ if (__DEV__) {
|
|||
|
||||
if (
|
||||
typeof value === 'boolean' &&
|
||||
!DOMProperty.shouldAttributeAcceptBooleanValue(name)
|
||||
!shouldAttributeAcceptBooleanValue(name)
|
||||
) {
|
||||
if (value) {
|
||||
warning(
|
||||
|
@ -220,7 +224,7 @@ if (__DEV__) {
|
|||
}
|
||||
|
||||
// Warn when a known attribute is a bad type
|
||||
if (!DOMProperty.shouldSetAttribute(name, value)) {
|
||||
if (!shouldSetAttribute(name, value)) {
|
||||
warnedProperties[name] = true;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import DOMProperty from './DOMProperty';
|
||||
import {injection} from './DOMProperty';
|
||||
|
||||
var {HAS_STRING_BOOLEAN_VALUE} = DOMProperty.injection;
|
||||
var {HAS_STRING_BOOLEAN_VALUE} = injection;
|
||||
|
||||
var NS = {
|
||||
xlink: 'http://www.w3.org/1999/xlink',
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import ReactDOM from 'react-dom';
|
||||
import EventPluginUtils from 'events/EventPluginUtils';
|
||||
import * as EventPluginUtils from 'events/EventPluginUtils';
|
||||
import ResponderEventPlugin from 'events/ResponderEventPlugin';
|
||||
import ResponderTouchHistoryStore from 'events/ResponderTouchHistoryStore';
|
||||
|
||||
|
|
|
@ -9,7 +9,10 @@
|
|||
|
||||
import type {ReactNativeBaseComponentViewConfig} from './ReactNativeTypes';
|
||||
|
||||
import EventPropagators from 'events/EventPropagators';
|
||||
import {
|
||||
accumulateTwoPhaseDispatches,
|
||||
accumulateDirectDispatches,
|
||||
} from 'events/EventPropagators';
|
||||
import SyntheticEvent from 'events/SyntheticEvent';
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
|
||||
|
@ -42,9 +45,9 @@ const ReactNativeBridgeEventPlugin = {
|
|||
nativeEventTarget,
|
||||
);
|
||||
if (bubbleDispatchConfig) {
|
||||
EventPropagators.accumulateTwoPhaseDispatches(event);
|
||||
accumulateTwoPhaseDispatches(event);
|
||||
} else if (directDispatchConfig) {
|
||||
EventPropagators.accumulateDirectDispatches(event);
|
||||
accumulateDirectDispatches(event);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@ import invariant from 'fbjs/lib/invariant';
|
|||
var instanceCache = {};
|
||||
var instanceProps = {};
|
||||
|
||||
function precacheFiberNode(hostInst, tag) {
|
||||
export function precacheFiberNode(hostInst, tag) {
|
||||
instanceCache[tag] = hostInst;
|
||||
}
|
||||
|
||||
function uncacheFiberNode(tag) {
|
||||
export function uncacheFiberNode(tag) {
|
||||
delete instanceCache[tag];
|
||||
delete instanceProps[tag];
|
||||
}
|
||||
|
@ -29,22 +29,16 @@ function getTagFromInstance(inst) {
|
|||
return tag;
|
||||
}
|
||||
|
||||
function getFiberCurrentPropsFromNode(stateNode) {
|
||||
export {
|
||||
getInstanceFromTag as getClosestInstanceFromNode,
|
||||
getInstanceFromTag as getInstanceFromNode,
|
||||
getTagFromInstance as getNodeFromInstance,
|
||||
};
|
||||
|
||||
export function getFiberCurrentPropsFromNode(stateNode) {
|
||||
return instanceProps[stateNode._nativeTag] || null;
|
||||
}
|
||||
|
||||
function updateFiberProps(tag, props) {
|
||||
export function updateFiberProps(tag, props) {
|
||||
instanceProps[tag] = props;
|
||||
}
|
||||
|
||||
var ReactNativeComponentTree = {
|
||||
getClosestInstanceFromNode: getInstanceFromTag,
|
||||
getInstanceFromNode: getInstanceFromTag,
|
||||
getNodeFromInstance: getTagFromInstance,
|
||||
precacheFiberNode,
|
||||
uncacheFiberNode,
|
||||
getFiberCurrentPropsFromNode,
|
||||
updateFiberProps,
|
||||
};
|
||||
|
||||
export default ReactNativeComponentTree;
|
||||
|
|
|
@ -7,15 +7,18 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import EventPluginHub from 'events/EventPluginHub';
|
||||
import EventPluginRegistry from 'events/EventPluginRegistry';
|
||||
import ReactEventEmitterMixin from 'events/ReactEventEmitterMixin';
|
||||
import ReactGenericBatching from 'events/ReactGenericBatching';
|
||||
import {getListener} from 'events/EventPluginHub';
|
||||
import {registrationNameModules} from 'events/EventPluginRegistry';
|
||||
import {batchedUpdates} from 'events/ReactGenericBatching';
|
||||
import {handleTopLevel} from 'events/ReactEventEmitterMixin';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
import ReactNativeComponentTree from './ReactNativeComponentTree';
|
||||
import {getInstanceFromNode} from './ReactNativeComponentTree';
|
||||
import ReactNativeTagHandles from './ReactNativeTagHandles';
|
||||
|
||||
export * from 'events/ReactEventEmitterMixin';
|
||||
export {getListener, registrationNameModules as registrationNames};
|
||||
|
||||
/**
|
||||
* Version of `ReactBrowserEventEmitter` that works on the receiving side of a
|
||||
* serialized worker boundary.
|
||||
|
@ -74,123 +77,101 @@ var removeTouchesAtIndices = function(
|
|||
return rippedOut;
|
||||
};
|
||||
|
||||
var ReactNativeEventEmitter = {
|
||||
...ReactEventEmitterMixin,
|
||||
/**
|
||||
* Internal version of `receiveEvent` in terms of normalized (non-tag)
|
||||
* `rootNodeID`.
|
||||
*
|
||||
* @see receiveEvent.
|
||||
*
|
||||
* @param {rootNodeID} rootNodeID React root node ID that event occurred on.
|
||||
* @param {TopLevelType} topLevelType Top level type of event.
|
||||
* @param {?object} nativeEventParam Object passed from native.
|
||||
*/
|
||||
export function _receiveRootNodeIDEvent(
|
||||
rootNodeID: number,
|
||||
topLevelType: string,
|
||||
nativeEventParam: ?Object,
|
||||
) {
|
||||
var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT;
|
||||
var inst = getInstanceFromNode(rootNodeID);
|
||||
batchedUpdates(function() {
|
||||
handleTopLevel(topLevelType, inst, nativeEvent, nativeEvent.target);
|
||||
});
|
||||
// React Native doesn't use ReactControlledComponent but if it did, here's
|
||||
// where it would do it.
|
||||
}
|
||||
|
||||
registrationNames: EventPluginRegistry.registrationNameModules,
|
||||
/**
|
||||
* Publicly exposed method on module for native objc to invoke when a top
|
||||
* level event is extracted.
|
||||
* @param {rootNodeID} rootNodeID React root node ID that event occurred on.
|
||||
* @param {TopLevelType} topLevelType Top level type of event.
|
||||
* @param {object} nativeEventParam Object passed from native.
|
||||
*/
|
||||
export function receiveEvent(
|
||||
rootNodeID: number,
|
||||
topLevelType: string,
|
||||
nativeEventParam: Object,
|
||||
) {
|
||||
_receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam);
|
||||
}
|
||||
|
||||
getListener: EventPluginHub.getListener,
|
||||
/**
|
||||
* Simple multi-wrapper around `receiveEvent` that is intended to receive an
|
||||
* efficient representation of `Touch` objects, and other information that
|
||||
* can be used to construct W3C compliant `Event` and `Touch` lists.
|
||||
*
|
||||
* This may create dispatch behavior that differs than web touch handling. We
|
||||
* loop through each of the changed touches and receive it as a single event.
|
||||
* So two `touchStart`/`touchMove`s that occur simultaneously are received as
|
||||
* two separate touch event dispatches - when they arguably should be one.
|
||||
*
|
||||
* This implementation reuses the `Touch` objects themselves as the `Event`s
|
||||
* since we dispatch an event for each touch (though that might not be spec
|
||||
* compliant). The main purpose of reusing them is to save allocations.
|
||||
*
|
||||
* TODO: Dispatch multiple changed touches in one event. The bubble path
|
||||
* could be the first common ancestor of all the `changedTouches`.
|
||||
*
|
||||
* One difference between this behavior and W3C spec: cancelled touches will
|
||||
* not appear in `.touches`, or in any future `.touches`, though they may
|
||||
* still be "actively touching the surface".
|
||||
*
|
||||
* Web desktop polyfills only need to construct a fake touch event with
|
||||
* identifier 0, also abandoning traditional click handlers.
|
||||
*/
|
||||
export function receiveTouches(
|
||||
eventTopLevelType: string,
|
||||
touches: Array<Object>,
|
||||
changedIndices: Array<number>,
|
||||
) {
|
||||
var changedTouches = eventTopLevelType === 'topTouchEnd' ||
|
||||
eventTopLevelType === 'topTouchCancel'
|
||||
? removeTouchesAtIndices(touches, changedIndices)
|
||||
: touchSubsequence(touches, changedIndices);
|
||||
|
||||
/**
|
||||
* Internal version of `receiveEvent` in terms of normalized (non-tag)
|
||||
* `rootNodeID`.
|
||||
*
|
||||
* @see receiveEvent.
|
||||
*
|
||||
* @param {rootNodeID} rootNodeID React root node ID that event occurred on.
|
||||
* @param {TopLevelType} topLevelType Top level type of event.
|
||||
* @param {?object} nativeEventParam Object passed from native.
|
||||
*/
|
||||
_receiveRootNodeIDEvent: function(
|
||||
rootNodeID: number,
|
||||
topLevelType: string,
|
||||
nativeEventParam: ?Object,
|
||||
) {
|
||||
var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT;
|
||||
var inst = ReactNativeComponentTree.getInstanceFromNode(rootNodeID);
|
||||
ReactGenericBatching.batchedUpdates(function() {
|
||||
ReactNativeEventEmitter.handleTopLevel(
|
||||
topLevelType,
|
||||
inst,
|
||||
nativeEvent,
|
||||
nativeEvent.target,
|
||||
);
|
||||
});
|
||||
// React Native doesn't use ReactControlledComponent but if it did, here's
|
||||
// where it would do it.
|
||||
},
|
||||
|
||||
/**
|
||||
* Publicly exposed method on module for native objc to invoke when a top
|
||||
* level event is extracted.
|
||||
* @param {rootNodeID} rootNodeID React root node ID that event occurred on.
|
||||
* @param {TopLevelType} topLevelType Top level type of event.
|
||||
* @param {object} nativeEventParam Object passed from native.
|
||||
*/
|
||||
receiveEvent: function(
|
||||
rootNodeID: number,
|
||||
topLevelType: string,
|
||||
nativeEventParam: Object,
|
||||
) {
|
||||
ReactNativeEventEmitter._receiveRootNodeIDEvent(
|
||||
rootNodeID,
|
||||
topLevelType,
|
||||
nativeEventParam,
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Simple multi-wrapper around `receiveEvent` that is intended to receive an
|
||||
* efficient representation of `Touch` objects, and other information that
|
||||
* can be used to construct W3C compliant `Event` and `Touch` lists.
|
||||
*
|
||||
* This may create dispatch behavior that differs than web touch handling. We
|
||||
* loop through each of the changed touches and receive it as a single event.
|
||||
* So two `touchStart`/`touchMove`s that occur simultaneously are received as
|
||||
* two separate touch event dispatches - when they arguably should be one.
|
||||
*
|
||||
* This implementation reuses the `Touch` objects themselves as the `Event`s
|
||||
* since we dispatch an event for each touch (though that might not be spec
|
||||
* compliant). The main purpose of reusing them is to save allocations.
|
||||
*
|
||||
* TODO: Dispatch multiple changed touches in one event. The bubble path
|
||||
* could be the first common ancestor of all the `changedTouches`.
|
||||
*
|
||||
* One difference between this behavior and W3C spec: cancelled touches will
|
||||
* not appear in `.touches`, or in any future `.touches`, though they may
|
||||
* still be "actively touching the surface".
|
||||
*
|
||||
* Web desktop polyfills only need to construct a fake touch event with
|
||||
* identifier 0, also abandoning traditional click handlers.
|
||||
*/
|
||||
receiveTouches: function(
|
||||
eventTopLevelType: string,
|
||||
touches: Array<Object>,
|
||||
changedIndices: Array<number>,
|
||||
) {
|
||||
var changedTouches = eventTopLevelType === 'topTouchEnd' ||
|
||||
eventTopLevelType === 'topTouchCancel'
|
||||
? removeTouchesAtIndices(touches, changedIndices)
|
||||
: touchSubsequence(touches, changedIndices);
|
||||
|
||||
for (var jj = 0; jj < changedTouches.length; jj++) {
|
||||
var touch = changedTouches[jj];
|
||||
// Touch objects can fulfill the role of `DOM` `Event` objects if we set
|
||||
// the `changedTouches`/`touches`. This saves allocations.
|
||||
touch.changedTouches = changedTouches;
|
||||
touch.touches = touches;
|
||||
var nativeEvent = touch;
|
||||
var rootNodeID = null;
|
||||
var target = nativeEvent.target;
|
||||
if (target !== null && target !== undefined) {
|
||||
if (target < ReactNativeTagHandles.tagsStartAt) {
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
false,
|
||||
'A view is reporting that a touch occurred on tag zero.',
|
||||
);
|
||||
}
|
||||
} else {
|
||||
rootNodeID = target;
|
||||
for (var jj = 0; jj < changedTouches.length; jj++) {
|
||||
var touch = changedTouches[jj];
|
||||
// Touch objects can fulfill the role of `DOM` `Event` objects if we set
|
||||
// the `changedTouches`/`touches`. This saves allocations.
|
||||
touch.changedTouches = changedTouches;
|
||||
touch.touches = touches;
|
||||
var nativeEvent = touch;
|
||||
var rootNodeID = null;
|
||||
var target = nativeEvent.target;
|
||||
if (target !== null && target !== undefined) {
|
||||
if (target < ReactNativeTagHandles.tagsStartAt) {
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
false,
|
||||
'A view is reporting that a touch occurred on tag zero.',
|
||||
);
|
||||
}
|
||||
} else {
|
||||
rootNodeID = target;
|
||||
}
|
||||
ReactNativeEventEmitter._receiveRootNodeIDEvent(
|
||||
rootNodeID,
|
||||
eventTopLevelType,
|
||||
nativeEvent,
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default ReactNativeEventEmitter;
|
||||
// $FlowFixMe Shouldn't we *not* call it if rootNodeID is null?
|
||||
_receiveRootNodeIDEvent(rootNodeID, eventTopLevelType, nativeEvent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,8 @@ import invariant from 'fbjs/lib/invariant';
|
|||
// Module provided by RN:
|
||||
import UIManager from 'UIManager';
|
||||
|
||||
import ReactNativeComponentTree from './ReactNativeComponentTree';
|
||||
import {getClosestInstanceFromNode} from './ReactNativeComponentTree';
|
||||
|
||||
const {getClosestInstanceFromNode} = ReactNativeComponentTree;
|
||||
let getInspectorDataForViewTag;
|
||||
|
||||
if (__DEV__) {
|
||||
|
|
|
@ -20,16 +20,14 @@ import deepFreezeAndThrowOnMutationInDev
|
|||
import * as ReactNativeViewConfigRegistry
|
||||
from './ReactNativeViewConfigRegistry';
|
||||
import * as ReactNativeAttributePayload from './ReactNativeAttributePayload';
|
||||
import ReactNativeComponentTree from './ReactNativeComponentTree';
|
||||
import ReactNativeFiberHostComponent from './ReactNativeFiberHostComponent';
|
||||
import * as ReactNativeFrameScheduling from './ReactNativeFrameScheduling';
|
||||
import ReactNativeTagHandles from './ReactNativeTagHandles';
|
||||
|
||||
const {
|
||||
import {
|
||||
precacheFiberNode,
|
||||
uncacheFiberNode,
|
||||
updateFiberProps,
|
||||
} = ReactNativeComponentTree;
|
||||
} from './ReactNativeComponentTree';
|
||||
import ReactNativeFiberHostComponent from './ReactNativeFiberHostComponent';
|
||||
import * as ReactNativeFrameScheduling from './ReactNativeFrameScheduling';
|
||||
import ReactNativeTagHandles from './ReactNativeTagHandles';
|
||||
|
||||
export type Container = number;
|
||||
export type Instance = {
|
||||
|
|
|
@ -16,15 +16,15 @@
|
|||
// Module provided by RN:
|
||||
import 'InitializeCore';
|
||||
|
||||
import EventPluginHub from 'events/EventPluginHub';
|
||||
import EventPluginUtils from 'events/EventPluginUtils';
|
||||
import * as EventPluginHub from 'events/EventPluginHub';
|
||||
import * as EventPluginUtils from 'events/EventPluginUtils';
|
||||
import ResponderEventPlugin from 'events/ResponderEventPlugin';
|
||||
// Module provided by RN:
|
||||
import RCTEventEmitter from 'RCTEventEmitter';
|
||||
|
||||
import ReactNativeBridgeEventPlugin from './ReactNativeBridgeEventPlugin';
|
||||
import ReactNativeComponentTree from './ReactNativeComponentTree';
|
||||
import ReactNativeEventEmitter from './ReactNativeEventEmitter';
|
||||
import * as ReactNativeComponentTree from './ReactNativeComponentTree';
|
||||
import * as ReactNativeEventEmitter from './ReactNativeEventEmitter';
|
||||
import ReactNativeEventPluginOrder from './ReactNativeEventPluginOrder';
|
||||
import ReactNativeGlobalResponderHandler
|
||||
from './ReactNativeGlobalResponderHandler';
|
||||
|
|
|
@ -17,7 +17,7 @@ import * as ReactFiberErrorLogger
|
|||
from 'react-reconciler/src/ReactFiberErrorLogger';
|
||||
import * as ReactPortal from 'react-reconciler/src/ReactPortal';
|
||||
import {injectInternals} from 'react-reconciler/src/ReactFiberDevToolsHook';
|
||||
import ReactGenericBatching from 'events/ReactGenericBatching';
|
||||
import * as ReactGenericBatching from 'events/ReactGenericBatching';
|
||||
import TouchHistoryMath from 'events/TouchHistoryMath';
|
||||
import * as ReactGlobalSharedState from 'shared/ReactGlobalSharedState';
|
||||
import ReactVersion from 'shared/ReactVersion';
|
||||
|
@ -28,7 +28,7 @@ import {showDialog} from './ReactNativeFiberErrorDialog';
|
|||
import NativeMethodsMixin from './NativeMethodsMixin';
|
||||
import ReactNativeBridgeEventPlugin from './ReactNativeBridgeEventPlugin';
|
||||
import ReactNativeComponent from './ReactNativeComponent';
|
||||
import ReactNativeComponentTree from './ReactNativeComponentTree';
|
||||
import * as ReactNativeComponentTree from './ReactNativeComponentTree';
|
||||
import ReactNativeFiberRenderer from './ReactNativeFiberRenderer';
|
||||
import ReactNativePropRegistry from './ReactNativePropRegistry';
|
||||
import {getInspectorDataForViewTag} from './ReactNativeFiberInspector';
|
||||
|
|
|
@ -18,10 +18,10 @@ import {
|
|||
} from 'react-native-renderer/src/ReactNativeFiberErrorDialog';
|
||||
import * as ReactPortal from 'react-reconciler/src/ReactPortal';
|
||||
import {injectInternals} from 'react-reconciler/src/ReactFiberDevToolsHook';
|
||||
import ReactGenericBatching from 'events/ReactGenericBatching';
|
||||
import * as ReactGenericBatching from 'events/ReactGenericBatching';
|
||||
import ReactVersion from 'shared/ReactVersion';
|
||||
|
||||
import ReactNativeRTComponentTree from './ReactNativeRTComponentTree';
|
||||
import {getFiberFromTag} from './ReactNativeRTComponentTree';
|
||||
import ReactNativeRTFiberRenderer from './ReactNativeRTFiberRenderer';
|
||||
import ReactNativeRTFiberInspector from './ReactNativeRTFiberInspector';
|
||||
|
||||
|
@ -84,7 +84,7 @@ const ReactNativeRTFiber: ReactNativeRTType = {
|
|||
};
|
||||
|
||||
injectInternals({
|
||||
findFiberByHostInstance: ReactNativeRTComponentTree.getFiberFromTag,
|
||||
findFiberByHostInstance: getFiberFromTag,
|
||||
findHostInstanceByFiber: ReactNativeRTFiberRenderer.findHostInstance,
|
||||
getInspectorDataForViewTag: ReactNativeRTFiberInspector.getInspectorDataForViewTag,
|
||||
// This is an enum because we may add more (e.g. profiler build)
|
||||
|
|
|
@ -12,33 +12,23 @@ import type {Fiber} from 'react-reconciler/src/ReactFiber';
|
|||
var instanceCache: {[key: number]: Fiber} = {};
|
||||
var instanceProps: {[key: number]: Object} = {};
|
||||
|
||||
function precacheFiberNode(fiber: Fiber, tag: number): void {
|
||||
export function precacheFiberNode(fiber: Fiber, tag: number): void {
|
||||
instanceCache[tag] = fiber;
|
||||
}
|
||||
|
||||
function getFiberFromTag(tag: number): null | Fiber {
|
||||
export function getFiberFromTag(tag: number): null | Fiber {
|
||||
return instanceCache[tag] || null;
|
||||
}
|
||||
|
||||
function uncacheFiberNode(tag: number): void {
|
||||
export function uncacheFiberNode(tag: number): void {
|
||||
delete instanceCache[tag];
|
||||
delete instanceProps[tag];
|
||||
}
|
||||
|
||||
function getFiberCurrentPropsFromTag(tag: number): null | Object {
|
||||
export function getFiberCurrentPropsFromTag(tag: number): null | Object {
|
||||
return instanceProps[tag] || null;
|
||||
}
|
||||
|
||||
function updateFiberProps(tag: number, props: Object): void {
|
||||
export function updateFiberProps(tag: number, props: Object): void {
|
||||
instanceProps[tag] = props;
|
||||
}
|
||||
|
||||
var ReactNativeRTComponentTree = {
|
||||
precacheFiberNode,
|
||||
uncacheFiberNode,
|
||||
getFiberFromTag,
|
||||
getFiberCurrentPropsFromTag,
|
||||
updateFiberProps,
|
||||
};
|
||||
|
||||
export default ReactNativeRTComponentTree;
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import ReactGenericBatching from 'events/ReactGenericBatching';
|
||||
import {batchedUpdates} from 'events/ReactGenericBatching';
|
||||
// Module provided by RN:
|
||||
import BatchedBridge from 'BatchedBridge';
|
||||
|
||||
import ReactNativeRTComponentTree from './ReactNativeRTComponentTree';
|
||||
import {getFiberCurrentPropsFromTag} from './ReactNativeRTComponentTree';
|
||||
|
||||
var ReactNativeRTEventEmitter = {
|
||||
/**
|
||||
|
@ -27,7 +27,7 @@ var ReactNativeRTEventEmitter = {
|
|||
nativeEventParam: Object,
|
||||
) {
|
||||
var nativeEvent = nativeEventParam;
|
||||
var props = ReactNativeRTComponentTree.getFiberCurrentPropsFromTag(tag);
|
||||
var props = getFiberCurrentPropsFromTag(tag);
|
||||
if (props == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ var ReactNativeRTEventEmitter = {
|
|||
if (typeof eventHandler !== 'function') {
|
||||
return;
|
||||
}
|
||||
ReactGenericBatching.batchedUpdates(function() {
|
||||
batchedUpdates(function() {
|
||||
eventHandler(nativeEvent);
|
||||
});
|
||||
},
|
||||
|
|
|
@ -16,9 +16,8 @@ import {HostComponent} from 'shared/ReactTypeOfWork';
|
|||
import emptyObject from 'fbjs/lib/emptyObject';
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
|
||||
import ReactNativeRTComponentTree from './ReactNativeRTComponentTree';
|
||||
import {getFiberFromTag} from './ReactNativeRTComponentTree';
|
||||
|
||||
const {getFiberFromTag} = ReactNativeRTComponentTree;
|
||||
let getInspectorDataForViewTag;
|
||||
|
||||
if (__DEV__) {
|
||||
|
|
|
@ -13,7 +13,10 @@ import invariant from 'fbjs/lib/invariant';
|
|||
// Module provided by RN:
|
||||
import RTManager from 'RTManager';
|
||||
|
||||
import ReactNativeRTComponentTree from './ReactNativeRTComponentTree';
|
||||
import {
|
||||
precacheFiberNode,
|
||||
updateFiberProps,
|
||||
} from './ReactNativeRTComponentTree';
|
||||
import ReactNativeRTTagHandles from './ReactNativeRTTagHandles';
|
||||
|
||||
export type Container = number;
|
||||
|
@ -21,8 +24,6 @@ export type Instance = number;
|
|||
export type Props = Object;
|
||||
export type TextInstance = number;
|
||||
|
||||
const {precacheFiberNode, updateFiberProps} = ReactNativeRTComponentTree;
|
||||
|
||||
function processProps(instance: number, props: Props): Object {
|
||||
const propsPayload = {};
|
||||
for (var key in props) {
|
||||
|
|
|
@ -11,7 +11,7 @@ import type {Fiber} from 'react-reconciler/src/ReactFiber';
|
|||
import type {FiberRoot} from 'react-reconciler/src/ReactFiberRoot';
|
||||
|
||||
import ReactFiberReconciler from 'react-reconciler';
|
||||
import ReactGenericBatching from 'events/ReactGenericBatching';
|
||||
import {batchedUpdates} from 'events/ReactGenericBatching';
|
||||
import {findCurrentFiberUsingSlowPath} from 'shared/ReactFiberTreeReflection';
|
||||
import emptyObject from 'fbjs/lib/emptyObject';
|
||||
import {
|
||||
|
@ -633,7 +633,7 @@ var ReactTestRendererFiber = {
|
|||
},
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
unstable_batchedUpdates: ReactGenericBatching.batchedUpdates,
|
||||
unstable_batchedUpdates: batchedUpdates,
|
||||
/* eslint-enable camelcase */
|
||||
};
|
||||
|
||||
|
|
|
@ -25,28 +25,28 @@
|
|||
"gzip": 6870
|
||||
},
|
||||
"react-dom.development.js (UMD_DEV)": {
|
||||
"size": 596493,
|
||||
"gzip": 134889
|
||||
"size": 589183,
|
||||
"gzip": 133823
|
||||
},
|
||||
"react-dom.production.min.js (UMD_PROD)": {
|
||||
"size": 100233,
|
||||
"gzip": 31848
|
||||
"size": 96544,
|
||||
"gzip": 31188
|
||||
},
|
||||
"react-dom.development.js (NODE_DEV)": {
|
||||
"size": 577466,
|
||||
"gzip": 130187
|
||||
"size": 570160,
|
||||
"gzip": 129121
|
||||
},
|
||||
"react-dom.production.min.js (NODE_PROD)": {
|
||||
"size": 98586,
|
||||
"gzip": 30972
|
||||
"size": 94731,
|
||||
"gzip": 30346
|
||||
},
|
||||
"ReactDOM-dev.js (FB_DEV)": {
|
||||
"size": 578317,
|
||||
"gzip": 130605
|
||||
"size": 571472,
|
||||
"gzip": 129612
|
||||
},
|
||||
"ReactDOM-prod.js (FB_PROD)": {
|
||||
"size": 412447,
|
||||
"gzip": 91219
|
||||
"size": 405312,
|
||||
"gzip": 90089
|
||||
},
|
||||
"react-dom-test-utils.development.js (NODE_DEV)": {
|
||||
"size": 37876,
|
||||
|
@ -61,60 +61,60 @@
|
|||
"gzip": 10182
|
||||
},
|
||||
"react-dom-unstable-native-dependencies.development.js (UMD_DEV)": {
|
||||
"size": 86323,
|
||||
"gzip": 20929
|
||||
"size": 66641,
|
||||
"gzip": 16671
|
||||
},
|
||||
"react-dom-unstable-native-dependencies.production.min.js (UMD_PROD)": {
|
||||
"size": 14157,
|
||||
"gzip": 4583
|
||||
"size": 11349,
|
||||
"gzip": 3900
|
||||
},
|
||||
"react-dom-unstable-native-dependencies.development.js (NODE_DEV)": {
|
||||
"size": 81826,
|
||||
"gzip": 19703
|
||||
"size": 62184,
|
||||
"gzip": 15356
|
||||
},
|
||||
"react-dom-unstable-native-dependencies.production.min.js (NODE_PROD)": {
|
||||
"size": 13707,
|
||||
"gzip": 4458
|
||||
"size": 10892,
|
||||
"gzip": 3771
|
||||
},
|
||||
"ReactDOMUnstableNativeDependencies-dev.js (FB_DEV)": {
|
||||
"size": 81123,
|
||||
"gzip": 19537
|
||||
"size": 61607,
|
||||
"gzip": 15197
|
||||
},
|
||||
"ReactDOMUnstableNativeDependencies-prod.js (FB_PROD)": {
|
||||
"size": 65265,
|
||||
"gzip": 15254
|
||||
"size": 52139,
|
||||
"gzip": 12586
|
||||
},
|
||||
"react-dom-server.browser.development.js (UMD_DEV)": {
|
||||
"size": 107196,
|
||||
"gzip": 27472
|
||||
"size": 100894,
|
||||
"gzip": 26193
|
||||
},
|
||||
"react-dom-server.browser.production.min.js (UMD_PROD)": {
|
||||
"size": 15632,
|
||||
"gzip": 6077
|
||||
"size": 14713,
|
||||
"gzip": 5827
|
||||
},
|
||||
"react-dom-server.browser.development.js (NODE_DEV)": {
|
||||
"size": 96125,
|
||||
"gzip": 24739
|
||||
"size": 89851,
|
||||
"gzip": 23452
|
||||
},
|
||||
"react-dom-server.browser.production.min.js (NODE_PROD)": {
|
||||
"size": 15101,
|
||||
"gzip": 5920
|
||||
"size": 14188,
|
||||
"gzip": 5707
|
||||
},
|
||||
"ReactDOMServer-dev.js (FB_DEV)": {
|
||||
"size": 95444,
|
||||
"gzip": 24574
|
||||
"size": 89268,
|
||||
"gzip": 23281
|
||||
},
|
||||
"ReactDOMServer-prod.js (FB_PROD)": {
|
||||
"size": 45835,
|
||||
"gzip": 12001
|
||||
"size": 45175,
|
||||
"gzip": 11989
|
||||
},
|
||||
"react-dom-server.node.development.js (NODE_DEV)": {
|
||||
"size": 98291,
|
||||
"gzip": 25249
|
||||
"size": 92017,
|
||||
"gzip": 23960
|
||||
},
|
||||
"react-dom-server.node.production.min.js (NODE_PROD)": {
|
||||
"size": 15925,
|
||||
"gzip": 6228
|
||||
"size": 15013,
|
||||
"gzip": 6016
|
||||
},
|
||||
"react-art.development.js (UMD_DEV)": {
|
||||
"size": 361363,
|
||||
|
@ -141,40 +141,40 @@
|
|||
"gzip": 43024
|
||||
},
|
||||
"ReactNativeRenderer-dev.js (RN_DEV)": {
|
||||
"size": 268852,
|
||||
"gzip": 46028
|
||||
"size": 264248,
|
||||
"gzip": 45270
|
||||
},
|
||||
"ReactNativeRenderer-prod.js (RN_PROD)": {
|
||||
"size": 206992,
|
||||
"gzip": 35199
|
||||
"size": 202770,
|
||||
"gzip": 34504
|
||||
},
|
||||
"ReactRTRenderer-dev.js (RN_DEV)": {
|
||||
"size": 202141,
|
||||
"gzip": 33933
|
||||
"size": 195970,
|
||||
"gzip": 32882
|
||||
},
|
||||
"ReactRTRenderer-prod.js (RN_PROD)": {
|
||||
"size": 150536,
|
||||
"gzip": 24872
|
||||
"size": 143566,
|
||||
"gzip": 23595
|
||||
},
|
||||
"ReactCSRenderer-dev.js (RN_DEV)": {
|
||||
"size": 189508,
|
||||
"gzip": 31550
|
||||
"size": 189548,
|
||||
"gzip": 31563
|
||||
},
|
||||
"ReactCSRenderer-prod.js (RN_PROD)": {
|
||||
"size": 139346,
|
||||
"gzip": 22600
|
||||
"size": 139382,
|
||||
"gzip": 22608
|
||||
},
|
||||
"react-test-renderer.development.js (NODE_DEV)": {
|
||||
"size": 290743,
|
||||
"gzip": 60340
|
||||
"size": 284199,
|
||||
"gzip": 58944
|
||||
},
|
||||
"react-test-renderer.production.min.js (NODE_PROD)": {
|
||||
"size": 50251,
|
||||
"gzip": 15366
|
||||
"size": 47325,
|
||||
"gzip": 14489
|
||||
},
|
||||
"ReactTestRenderer-dev.js (FB_DEV)": {
|
||||
"size": 288988,
|
||||
"gzip": 60118
|
||||
"size": 282462,
|
||||
"gzip": 58722
|
||||
},
|
||||
"react-test-renderer-shallow.development.js (NODE_DEV)": {
|
||||
"size": 10657,
|
||||
|
|
Loading…
Reference in New Issue