mirror of
https://github.com/hanzoai/react.git
synced 2026-09-24 17:02:27 +00:00
ReactDOM.useEvent: more scaffolding changes (#18282)
This commit is contained in:
@@ -29,7 +29,7 @@ export type PluginModule<NativeEvent> = {
|
||||
nativeTarget: NativeEvent,
|
||||
nativeEventTarget: null | EventTarget,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
container?: Document | Element,
|
||||
container?: EventTarget,
|
||||
) => ?ReactSyntheticEvent,
|
||||
tapMoveThreshold?: number,
|
||||
};
|
||||
|
||||
@@ -34,4 +34,5 @@ export type ReactSyntheticEvent = {|
|
||||
_dispatchInstances: null | Array<Fiber>,
|
||||
_dispatchListeners: null | Array<Function>,
|
||||
_targetInst: null | Fiber,
|
||||
type: string,
|
||||
|};
|
||||
|
||||
+12
@@ -469,3 +469,15 @@ export function getInstanceFromNode(node) {
|
||||
export function beforeRemoveInstance(instance) {
|
||||
// noop
|
||||
}
|
||||
|
||||
export function mountEventListener(listener: any) {
|
||||
throw new Error('Not yet implemented.');
|
||||
}
|
||||
|
||||
export function unmountEventListener(listener: any) {
|
||||
throw new Error('Not yet implemented.');
|
||||
}
|
||||
|
||||
export function validateEventListenerTarget(target: any, listener: any) {
|
||||
throw new Error('Not yet implemented.');
|
||||
}
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ type HookLogEntry = {
|
||||
|
||||
type ReactDebugListenerMap = {|
|
||||
clear: () => void,
|
||||
setListener: (instance: EventTarget, callback: ?(Event) => void) => void,
|
||||
setListener: (target: EventTarget, callback: ?(Event) => void) => void,
|
||||
|};
|
||||
|
||||
let hookLog: Array<HookLogEntry> = [];
|
||||
|
||||
@@ -66,12 +66,17 @@ import {
|
||||
enableSuspenseServerRenderer,
|
||||
enableDeprecatedFlareAPI,
|
||||
enableFundamentalAPI,
|
||||
enableUseEventAPI,
|
||||
} from 'shared/ReactFeatureFlags';
|
||||
import {HostComponent} from 'shared/ReactWorkTags';
|
||||
import {
|
||||
RESPONDER_EVENT_SYSTEM,
|
||||
IS_PASSIVE,
|
||||
} from 'legacy-events/EventSystemFlags';
|
||||
import {
|
||||
attachElementListener,
|
||||
detachElementListener,
|
||||
} from '../events/DOMModernPluginEventSystem';
|
||||
|
||||
export type ReactListenerEvent = ReactDOMListenerEvent;
|
||||
export type ReactListenerMap = ReactDOMListenerMap;
|
||||
@@ -1075,3 +1080,63 @@ export function unmountFundamentalComponent(
|
||||
export function getInstanceFromNode(node: HTMLElement): null | Object {
|
||||
return getClosestInstanceFromNode(node) || null;
|
||||
}
|
||||
|
||||
export function mountEventListener(listener: ReactDOMListener): void {
|
||||
if (enableUseEventAPI) {
|
||||
const {target} = listener;
|
||||
if (target === window) {
|
||||
// TODO (useEvent)
|
||||
} else {
|
||||
attachElementListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function unmountEventListener(listener: ReactDOMListener): void {
|
||||
if (enableUseEventAPI) {
|
||||
const {target} = listener;
|
||||
if (target === window) {
|
||||
// TODO (useEvent)
|
||||
} else {
|
||||
detachElementListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function validateEventListenerTarget(
|
||||
target: EventTarget,
|
||||
listener: ?(Event) => void,
|
||||
): boolean {
|
||||
if (enableUseEventAPI) {
|
||||
if (
|
||||
target &&
|
||||
(target === window || getClosestInstanceFromNode(((target: any): Node)))
|
||||
) {
|
||||
if (listener == null || typeof listener === 'function') {
|
||||
return true;
|
||||
}
|
||||
if (__DEV__) {
|
||||
console.warn(
|
||||
'Event listener method setListener() from useEvent() hook requires the second argument' +
|
||||
' to be either a valid function callback or null/undefined.',
|
||||
);
|
||||
}
|
||||
}
|
||||
if (__DEV__) {
|
||||
if (target && (target: any).nodeType === DOCUMENT_NODE) {
|
||||
console.warn(
|
||||
'Event listener method setListener() from useEvent() hook requires the first argument to be a valid' +
|
||||
' DOM node that was rendered and managed by React or a "window" object. It looks like' +
|
||||
' you supplied a "document" node, instead use the "window" object.',
|
||||
);
|
||||
} else {
|
||||
console.warn(
|
||||
'Event listener method setListener() from useEvent() hook requires the first argument to be a valid' +
|
||||
' DOM node that was rendered and managed by React or a "window" object. If this is' +
|
||||
' from a ref, ensure the ref value has been set before attaching.',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
+4
-7
@@ -16,18 +16,15 @@ const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
|
||||
const elementListenerMap:
|
||||
// $FlowFixMe Work around Flow bug
|
||||
| WeakMap
|
||||
| Map<
|
||||
Document | Element | Node,
|
||||
Map<DOMTopLevelEventType | string, null | (any => void)>,
|
||||
> = new PossiblyWeakMap();
|
||||
| Map<EventTarget, Map<DOMTopLevelEventType | string, null | (any => void)>> = new PossiblyWeakMap();
|
||||
|
||||
export function getListenerMapForElement(
|
||||
element: Document | Element | Node,
|
||||
target: EventTarget,
|
||||
): Map<DOMTopLevelEventType | string, null | (any => void)> {
|
||||
let listenerMap = elementListenerMap.get(element);
|
||||
let listenerMap = elementListenerMap.get(target);
|
||||
if (listenerMap === undefined) {
|
||||
listenerMap = new Map();
|
||||
elementListenerMap.set(element, listenerMap);
|
||||
elementListenerMap.set(target, listenerMap);
|
||||
}
|
||||
return listenerMap;
|
||||
}
|
||||
|
||||
+13
-4
@@ -108,7 +108,7 @@ function dispatchEventsForPlugins(
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
targetInst: null | Fiber,
|
||||
rootContainer: Element | Document,
|
||||
rootContainer: EventTarget,
|
||||
): void {
|
||||
const nativeEventTarget = getEventTarget(nativeEvent);
|
||||
const syntheticEvents: Array<ReactSyntheticEvent> = [];
|
||||
@@ -209,7 +209,7 @@ function willDeferLaterForFBLegacyPrimer(nativeEvent: any): boolean {
|
||||
|
||||
function isMatchingRootContainer(
|
||||
grandContainer: Element,
|
||||
rootContainer: Document | Element,
|
||||
rootContainer: EventTarget,
|
||||
): boolean {
|
||||
return (
|
||||
grandContainer === rootContainer ||
|
||||
@@ -223,10 +223,19 @@ export function dispatchEventForPluginEventSystem(
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
targetInst: null | Fiber,
|
||||
rootContainer: Document | Element,
|
||||
rootContainer: EventTarget,
|
||||
): void {
|
||||
let ancestorInst = targetInst;
|
||||
if (rootContainer.nodeType !== DOCUMENT_NODE) {
|
||||
// Given the rootContainer can be any EventTarget, if the
|
||||
// target is that of a DOM node (other than the document)
|
||||
// then we'll attempt to find the correct ancestor root.
|
||||
// Note: the rootContainer can be other things like
|
||||
// "window" or other valid EventTarget objects.
|
||||
const possibleContainerNodeType = ((rootContainer: any): Node).nodeType;
|
||||
if (
|
||||
possibleContainerNodeType !== undefined &&
|
||||
possibleContainerNodeType !== DOCUMENT_NODE
|
||||
) {
|
||||
// If we detect the FB legacy primer system, we
|
||||
// defer the event to the "document" with a one
|
||||
// time event listener so we can defer the event.
|
||||
|
||||
+17
-6
@@ -8,29 +8,40 @@
|
||||
*/
|
||||
|
||||
export function addEventBubbleListener(
|
||||
element: Document | Element | Node,
|
||||
target: EventTarget,
|
||||
eventType: string,
|
||||
listener: Function,
|
||||
): void {
|
||||
element.addEventListener(eventType, listener, false);
|
||||
target.addEventListener(eventType, listener, false);
|
||||
}
|
||||
|
||||
export function addEventCaptureListener(
|
||||
element: Document | Element | Node,
|
||||
target: EventTarget,
|
||||
eventType: string,
|
||||
listener: Function,
|
||||
): void {
|
||||
element.addEventListener(eventType, listener, true);
|
||||
target.addEventListener(eventType, listener, true);
|
||||
}
|
||||
|
||||
export function addEventCaptureListenerWithPassiveFlag(
|
||||
element: Document | Element | Node,
|
||||
target: EventTarget,
|
||||
eventType: string,
|
||||
listener: Function,
|
||||
passive: boolean,
|
||||
): void {
|
||||
element.addEventListener(eventType, listener, {
|
||||
target.addEventListener(eventType, listener, {
|
||||
capture: true,
|
||||
passive,
|
||||
});
|
||||
}
|
||||
|
||||
export function addEventBubbleListenerWithPassiveFlag(
|
||||
target: EventTarget,
|
||||
eventType: string,
|
||||
listener: Function,
|
||||
passive: boolean,
|
||||
): void {
|
||||
target.addEventListener(eventType, listener, {
|
||||
passive,
|
||||
});
|
||||
}
|
||||
|
||||
+18
-10
@@ -130,7 +130,7 @@ export function addResponderEventSystemEvent(
|
||||
}
|
||||
|
||||
export function addTrappedEventListener(
|
||||
container: Document | Element,
|
||||
targetContainer: EventTarget,
|
||||
topLevelType: DOMTopLevelEventType,
|
||||
capture: boolean,
|
||||
legacyFBSupport?: boolean,
|
||||
@@ -153,7 +153,7 @@ export function addTrappedEventListener(
|
||||
null,
|
||||
topLevelType,
|
||||
PLUGIN_EVENT_SYSTEM,
|
||||
container,
|
||||
targetContainer,
|
||||
);
|
||||
|
||||
const rawEventName = getRawEventName(topLevelType);
|
||||
@@ -179,7 +179,7 @@ export function addTrappedEventListener(
|
||||
if (fbListener) {
|
||||
fbListener.remove();
|
||||
} else {
|
||||
container.removeEventListener(
|
||||
targetContainer.removeEventListener(
|
||||
((rawEventName: any): string),
|
||||
(listener: any),
|
||||
);
|
||||
@@ -188,9 +188,17 @@ export function addTrappedEventListener(
|
||||
};
|
||||
}
|
||||
if (capture) {
|
||||
fbListener = addEventCaptureListener(container, rawEventName, listener);
|
||||
fbListener = addEventCaptureListener(
|
||||
targetContainer,
|
||||
rawEventName,
|
||||
listener,
|
||||
);
|
||||
} else {
|
||||
fbListener = addEventBubbleListener(container, rawEventName, listener);
|
||||
fbListener = addEventBubbleListener(
|
||||
targetContainer,
|
||||
rawEventName,
|
||||
listener,
|
||||
);
|
||||
}
|
||||
// If we have an fbListener, then use that.
|
||||
// We'll only have one if we use the forked
|
||||
@@ -199,7 +207,7 @@ export function addTrappedEventListener(
|
||||
}
|
||||
|
||||
export function removeTrappedPassiveEventListener(
|
||||
document: Document,
|
||||
targetContainer: EventTarget,
|
||||
topLevelType: string,
|
||||
listener: any => void,
|
||||
) {
|
||||
@@ -207,12 +215,12 @@ export function removeTrappedPassiveEventListener(
|
||||
listener.remove();
|
||||
} else {
|
||||
if (passiveBrowserEventsSupported) {
|
||||
document.removeEventListener(topLevelType, listener, {
|
||||
targetContainer.removeEventListener(topLevelType, listener, {
|
||||
capture: true,
|
||||
passive: true,
|
||||
});
|
||||
} else {
|
||||
document.removeEventListener(topLevelType, listener, true);
|
||||
targetContainer.removeEventListener(topLevelType, listener, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,7 +262,7 @@ function dispatchUserBlockingUpdate(
|
||||
export function dispatchEvent(
|
||||
topLevelType: DOMTopLevelEventType,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
container: Document | Element,
|
||||
container: EventTarget,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
): void {
|
||||
if (!_enabled) {
|
||||
@@ -370,7 +378,7 @@ export function dispatchEvent(
|
||||
export function attemptToDispatchEvent(
|
||||
topLevelType: DOMTopLevelEventType,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
container: Document | Element,
|
||||
container: EventTarget,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
): null | Container | SuspenseInstance {
|
||||
// TODO: Warn if _enabled is false.
|
||||
|
||||
+5
-5
@@ -126,7 +126,7 @@ type QueuedReplayableEvent = {|
|
||||
topLevelType: DOMTopLevelEventType,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
container: Document | Element,
|
||||
container: EventTarget,
|
||||
|};
|
||||
|
||||
let hasScheduledReplayAttempt = false;
|
||||
@@ -285,7 +285,7 @@ function createQueuedReplayableEvent(
|
||||
blockedOn: null | Container | SuspenseInstance,
|
||||
topLevelType: DOMTopLevelEventType,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
container: Document | Element,
|
||||
container: EventTarget,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
): QueuedReplayableEvent {
|
||||
return {
|
||||
@@ -301,7 +301,7 @@ export function queueDiscreteEvent(
|
||||
blockedOn: null | Container | SuspenseInstance,
|
||||
topLevelType: DOMTopLevelEventType,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
container: Document | Element,
|
||||
container: EventTarget,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
): void {
|
||||
const queuedEvent = createQueuedReplayableEvent(
|
||||
@@ -376,7 +376,7 @@ function accumulateOrCreateContinuousQueuedReplayableEvent(
|
||||
blockedOn: null | Container | SuspenseInstance,
|
||||
topLevelType: DOMTopLevelEventType,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
container: Document | Element,
|
||||
container: EventTarget,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
): QueuedReplayableEvent {
|
||||
if (
|
||||
@@ -411,7 +411,7 @@ export function queueIfContinuousEvent(
|
||||
blockedOn: null | Container | SuspenseInstance,
|
||||
topLevelType: DOMTopLevelEventType,
|
||||
eventSystemFlags: EventSystemFlags,
|
||||
container: Document | Element,
|
||||
container: EventTarget,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
): boolean {
|
||||
// These set relatedTarget to null because the replayed event will be treated as if we
|
||||
|
||||
+20
-6
@@ -13,29 +13,43 @@ import typeof * as EventListenerType from '../EventListener';
|
||||
import typeof * as EventListenerShimType from './EventListener-www';
|
||||
|
||||
export function addEventBubbleListener(
|
||||
element: Element,
|
||||
target: EventTarget,
|
||||
eventType: string,
|
||||
listener: Function,
|
||||
) {
|
||||
return EventListenerWWW.listen(element, eventType, listener);
|
||||
return EventListenerWWW.listen(target, eventType, listener);
|
||||
}
|
||||
|
||||
export function addEventCaptureListener(
|
||||
element: Element,
|
||||
target: EventTarget,
|
||||
eventType: string,
|
||||
listener: Function,
|
||||
) {
|
||||
return EventListenerWWW.capture(element, eventType, listener);
|
||||
return EventListenerWWW.capture(target, eventType, listener);
|
||||
}
|
||||
|
||||
export function addEventCaptureListenerWithPassiveFlag(
|
||||
element: Element,
|
||||
target: EventTarget,
|
||||
eventType: string,
|
||||
listener: Function,
|
||||
passive: boolean,
|
||||
) {
|
||||
return EventListenerWWW.captureWithPassiveFlag(
|
||||
element,
|
||||
target,
|
||||
eventType,
|
||||
listener,
|
||||
passive,
|
||||
);
|
||||
}
|
||||
|
||||
export function addEventBubbleListenerWithPassiveFlag(
|
||||
target: EventTarget,
|
||||
eventType: string,
|
||||
listener: Function,
|
||||
passive: boolean,
|
||||
) {
|
||||
return EventListenerWWW.bubbleWithPassiveFlag(
|
||||
target,
|
||||
eventType,
|
||||
listener,
|
||||
passive,
|
||||
|
||||
@@ -473,3 +473,15 @@ export function getInstanceFromNode(node: any) {
|
||||
export function beforeRemoveInstance(instance: any) {
|
||||
// noop
|
||||
}
|
||||
|
||||
export function mountEventListener(listener: any) {
|
||||
throw new Error('Not yet implemented.');
|
||||
}
|
||||
|
||||
export function unmountEventListener(listener: any) {
|
||||
throw new Error('Not yet implemented.');
|
||||
}
|
||||
|
||||
export function validateEventListenerTarget(target: any, listener: any) {
|
||||
throw new Error('Not yet implemented.');
|
||||
}
|
||||
|
||||
@@ -517,3 +517,15 @@ export function getInstanceFromNode(node: any) {
|
||||
export function beforeRemoveInstance(instance: any) {
|
||||
// noop
|
||||
}
|
||||
|
||||
export function mountEventListener(listener: any) {
|
||||
throw new Error('Not yet implemented.');
|
||||
}
|
||||
|
||||
export function unmountEventListener(listener: any) {
|
||||
throw new Error('Not yet implemented.');
|
||||
}
|
||||
|
||||
export function validateEventListenerTarget(target: any, listener: any) {
|
||||
throw new Error('Not yet implemented.');
|
||||
}
|
||||
|
||||
@@ -76,6 +76,10 @@ export const shouldUpdateFundamentalComponent =
|
||||
$$$hostConfig.shouldUpdateFundamentalComponent;
|
||||
export const getInstanceFromNode = $$$hostConfig.getInstanceFromNode;
|
||||
export const beforeRemoveInstance = $$$hostConfig.beforeRemoveInstance;
|
||||
export const mountEventListener = $$$hostConfig.mountEventListener;
|
||||
export const unmountEventListener = $$$hostConfig.unmountEventListener;
|
||||
export const validateEventListenerTarget =
|
||||
$$$hostConfig.validateEventListenerTarget;
|
||||
|
||||
// -------------------
|
||||
// Mutation
|
||||
|
||||
@@ -379,3 +379,15 @@ export function getInstanceFromNode(mockNode: Object) {
|
||||
export function beforeRemoveInstance(instance: any) {
|
||||
// noop
|
||||
}
|
||||
|
||||
export function mountEventListener(listener: any) {
|
||||
throw new Error('Not yet implemented.');
|
||||
}
|
||||
|
||||
export function unmountEventListener(listener: any) {
|
||||
throw new Error('Not yet implemented.');
|
||||
}
|
||||
|
||||
export function validateEventListenerTarget(target: any, listener: any) {
|
||||
throw new Error('Not yet implemented.');
|
||||
}
|
||||
|
||||
@@ -85,13 +85,12 @@ export type ReactDOMListenerEvent = {|
|
||||
|
||||
export type ReactDOMListenerMap = {|
|
||||
clear: () => void,
|
||||
setListener: (instance: EventTarget, callback: ?(Event) => void) => void,
|
||||
setListener: (target: EventTarget, callback: ?(Event) => void) => void,
|
||||
|};
|
||||
|
||||
export type ReactDOMListener = {|
|
||||
callback: Event => void,
|
||||
depth: number,
|
||||
destroy: Document | (Element => void),
|
||||
destroy: Node => void,
|
||||
event: ReactDOMListenerEvent,
|
||||
instance: EventTarget,
|
||||
target: EventTarget,
|
||||
|};
|
||||
|
||||
@@ -44,15 +44,21 @@ declare module 'ReactFiberErrorDialog' {
|
||||
declare module 'EventListener' {
|
||||
declare module.exports: {
|
||||
listen: (
|
||||
target: Element,
|
||||
target: EventTarget,
|
||||
type: string,
|
||||
callback: Function,
|
||||
priority?: number,
|
||||
options?: {passive: boolean, ...},
|
||||
) => mixed,
|
||||
capture: (target: Element, type: string, callback: Function) => mixed,
|
||||
capture: (target: EventTarget, type: string, callback: Function) => mixed,
|
||||
captureWithPassiveFlag: (
|
||||
target: Element,
|
||||
target: EventTarget,
|
||||
type: string,
|
||||
callback: Function,
|
||||
passive: boolean,
|
||||
) => mixed,
|
||||
bubbleWithPassiveFlag: (
|
||||
target: EventTarget,
|
||||
type: string,
|
||||
callback: Function,
|
||||
passive: boolean,
|
||||
|
||||
Reference in New Issue
Block a user