diff --git a/packages/react-native-web/src/modules/createEventHandle/__tests__/index-test.js b/packages/react-native-web/src/modules/addEventListener/__tests__/index-test.js similarity index 75% rename from packages/react-native-web/src/modules/createEventHandle/__tests__/index-test.js rename to packages/react-native-web/src/modules/addEventListener/__tests__/index-test.js index f62e22ef95..2dea25f69a 100644 --- a/packages/react-native-web/src/modules/createEventHandle/__tests__/index-test.js +++ b/packages/react-native-web/src/modules/addEventListener/__tests__/index-test.js @@ -10,18 +10,17 @@ import * as React from 'react'; import { act, render } from '@testing-library/react'; import { createEventTarget } from 'dom-event-testing-library'; -import createEventHandle from '..'; +import { addEventListener } from '..'; -describe('create-event-handle', () => { - describe('createEventTarget()', () => { +describe('addEventListener', () => { + describe('addEventListener()', () => { test('event dispatched on target', () => { const listener = jest.fn(); const targetRef = React.createRef(); - const addClickListener = createEventHandle('click'); function Component() { React.useEffect(() => { - return addClickListener(targetRef.current, listener); + return addEventListener(targetRef.current, 'click', listener); }); return
; } @@ -42,20 +41,19 @@ describe('create-event-handle', () => { const listenerCapture = jest.fn(); const targetRef = React.createRef(); const parentRef = React.createRef(); - const addClickListener = createEventHandle('click'); - const addClickCaptureListener = createEventHandle('click', { - capture: true - }); function Component() { React.useEffect(() => { - const removeClickListener = addClickListener( + const removeClickListener = addEventListener( targetRef.current, + 'click', listener ); - const removeClickCaptureListener = addClickCaptureListener( + const removeClickCaptureListener = addEventListener( targetRef.current, - listenerCapture + 'click', + listenerCapture, + { capture: true } ); return () => { removeClickListener(); @@ -91,20 +89,19 @@ describe('create-event-handle', () => { }); const targetRef = React.createRef(); const childRef = React.createRef(); - const addClickListener = createEventHandle('click'); - const addClickCaptureListener = createEventHandle('click', { - capture: true - }); function Component() { React.useEffect(() => { - const removeClickListener = addClickListener( + const removeClickListener = addEventListener( targetRef.current, + 'click', listener ); - const removeClickCaptureListener = addClickCaptureListener( + const removeClickCaptureListener = addEventListener( targetRef.current, - listenerCapture + 'click', + listenerCapture, + { capture: true } ); return () => { removeClickListener(); @@ -135,11 +132,10 @@ describe('create-event-handle', () => { const listener = jest.fn(); const targetRef = React.createRef(); const childRef = React.createRef(); - const addClickListener = createEventHandle('click'); function Component() { React.useEffect(() => { - return addClickListener(targetRef.current, listener); + return addEventListener(targetRef.current, 'click', listener); }); return (
@@ -162,11 +158,10 @@ describe('create-event-handle', () => { test('listener can be attached to document', () => { const listener = jest.fn(); const targetRef = React.createRef(); - const addClickListener = createEventHandle('click'); function Component({ target }) { React.useEffect(() => { - return addClickListener(target, listener); + return addEventListener(target, 'click', listener); }); return
; } @@ -184,11 +179,10 @@ describe('create-event-handle', () => { test('listener can be attached to window ', () => { const listener = jest.fn(); const targetRef = React.createRef(); - const addClickListener = createEventHandle('click'); function Component({ target }) { React.useEffect(() => { - return addClickListener(target, listener); + return addEventListener(target, 'click', listener); }); return
; } @@ -206,11 +200,10 @@ describe('create-event-handle', () => { test('custom event dispatched on target', () => { const listener = jest.fn(); const targetRef = React.createRef(); - const addMagicEventListener = createEventHandle('magic-event'); function Component() { React.useEffect(() => { - return addMagicEventListener(targetRef.current, listener); + return addEventListener(targetRef.current, 'magic-event', listener); }); return
; } @@ -230,10 +223,7 @@ describe('create-event-handle', () => { const targetRef = React.createRef(); const parentRef = React.createRef(); const childRef = React.createRef(); - const addClickListener = createEventHandle('click'); - const addClickCaptureListener = createEventHandle('click', { - capture: true - }); + const listener = jest.fn((e) => { log.push(['bubble', e.currentTarget.id]); }); @@ -244,10 +234,14 @@ describe('create-event-handle', () => { function Component() { React.useEffect(() => { // the same event handle is used to set listeners on different targets - addClickListener(targetRef.current, listener); - addClickListener(parentRef.current, listener); - addClickCaptureListener(targetRef.current, listenerCapture); - addClickCaptureListener(parentRef.current, listenerCapture); + addEventListener(targetRef.current, 'click', listener); + addEventListener(parentRef.current, 'click', listener); + addEventListener(targetRef.current, 'click', listenerCapture, { + capture: true + }); + addEventListener(parentRef.current, 'click', listenerCapture, { + capture: true + }); }); return (
@@ -280,14 +274,6 @@ describe('create-event-handle', () => { const log = []; const targetRef = React.createRef(); const childRef = React.createRef(); - const addClickListener = createEventHandle('click'); - const addClickAltListener = createEventHandle('click'); - const addClickCaptureListener = createEventHandle('click', { - capture: true - }); - const addClickCaptureAltListener = createEventHandle('click', { - capture: true - }); const listener = jest.fn((e) => { log.push(['bubble', 'target']); }); @@ -303,10 +289,14 @@ describe('create-event-handle', () => { function Component() { React.useEffect(() => { - addClickListener(targetRef.current, listener); - addClickAltListener(targetRef.current, listenerAlt); - addClickCaptureListener(targetRef.current, listenerCapture); - addClickCaptureAltListener(targetRef.current, listenerCaptureAlt); + addEventListener(targetRef.current, 'click', listener); + addEventListener(targetRef.current, 'click', listenerAlt); + addEventListener(targetRef.current, 'click', listenerCapture, { + capture: true + }); + addEventListener(targetRef.current, 'click', listenerCaptureAlt, { + capture: true + }); }); return (
@@ -344,12 +334,11 @@ describe('create-event-handle', () => { const targetListener = jest.fn(); const targetRef = React.createRef(); const childRef = React.createRef(); - const addClickListener = createEventHandle('click'); function Component() { React.useEffect(() => { - addClickListener(childRef.current, childListener); - addClickListener(targetRef.current, targetListener); + addEventListener(childRef.current, 'click', childListener); + addEventListener(targetRef.current, 'click', targetListener); }); return (
@@ -376,13 +365,11 @@ describe('create-event-handle', () => { }); const secondListener = jest.fn(); const targetRef = React.createRef(); - const addFirstClickListener = createEventHandle('click'); - const addSecondClickListener = createEventHandle('click'); function Component() { React.useEffect(() => { - addFirstClickListener(targetRef.current, firstListener); - addSecondClickListener(targetRef.current, secondListener); + addEventListener(targetRef.current, 'click', firstListener); + addEventListener(targetRef.current, 'click', secondListener); }); return
; } diff --git a/packages/react-native-web/src/modules/createEventHandle/__tests__/index-test.node.js b/packages/react-native-web/src/modules/addEventListener/__tests__/index-test.node.js similarity index 77% rename from packages/react-native-web/src/modules/createEventHandle/__tests__/index-test.node.js rename to packages/react-native-web/src/modules/addEventListener/__tests__/index-test.node.js index b9c7e0e6ef..11d0c501c4 100644 --- a/packages/react-native-web/src/modules/createEventHandle/__tests__/index-test.node.js +++ b/packages/react-native-web/src/modules/addEventListener/__tests__/index-test.node.js @@ -9,17 +9,16 @@ import * as React from 'react'; import * as ReactDOMServer from 'react-dom/server'; -import createEventHandle from '..'; +import { addEventListener } from '..'; -describe('create-event-handle', () => { +describe('addEventListener', () => { test('can render correctly using ReactDOMServer', () => { const listener = jest.fn(); const targetRef = React.createRef(); - const addClickListener = createEventHandle('click'); function Component() { React.useEffect(() => { - return addClickListener(targetRef.current, listener); + return addEventListener(targetRef.current, 'click', listener); }); return
; } diff --git a/packages/react-native-web/src/modules/createEventHandle/index.js b/packages/react-native-web/src/modules/addEventListener/index.js similarity index 70% rename from packages/react-native-web/src/modules/createEventHandle/index.js rename to packages/react-native-web/src/modules/addEventListener/index.js index bc2bf524b5..105486fc53 100644 --- a/packages/react-native-web/src/modules/createEventHandle/index.js +++ b/packages/react-native-web/src/modules/addEventListener/index.js @@ -12,11 +12,10 @@ import canUseDOM from '../canUseDom'; type Listener = (e: any) => void; -type EventHandle = (target: EventTarget, callback: ?Listener) => () => void; - export type EventOptions = { capture?: boolean, - passive?: boolean + passive?: boolean, + once?: boolean }; const emptyFunction = () => {}; @@ -72,28 +71,19 @@ function normalizeEvent(event: any) { /** * */ -export default function createEventHandle( - type: string, +export function addEventListener( + target: EventTarget, + type: any, + listener: Listener, options: ?EventOptions -): EventHandle { +): () => void { const opts = getOptions(options); + const compatListener = (e: any) => listener(normalizeEvent(e)); + target.addEventListener(type, compatListener, opts); - return function (target: EventTarget, listener: ?Listener) { - if (target == null || typeof target.addEventListener !== 'function') { - throw new Error('createEventHandle: called on an invalid target.'); - } - - const element = (target: any); - if (listener != null) { - const compatListener = (e) => listener(normalizeEvent(e)); - element.addEventListener(type, compatListener, opts); - return function removeListener() { - if (element != null) { - element.removeEventListener(type, compatListener, opts); - } - }; - } else { - return emptyFunction; + return function removeEventListener() { + if (target != null) { + target.removeEventListener(type, compatListener, opts); } }; } diff --git a/packages/react-native-web/src/modules/modality/index.js b/packages/react-native-web/src/modules/modality/index.js index a998ff02c5..dfdba393fe 100644 --- a/packages/react-native-web/src/modules/modality/index.js +++ b/packages/react-native-web/src/modules/modality/index.js @@ -7,7 +7,7 @@ * @flow */ -import createEventHandle from '../createEventHandle'; +import { addEventListener } from '../addEventListener'; import canUseDOM from '../canUseDom'; export type Modality = 'keyboard' | 'mouse' | 'touch' | 'pen'; @@ -45,32 +45,6 @@ const VISIBILITYCHANGE = 'visibilitychange'; const bubbleOptions = { passive: true }; const captureOptions = { capture: true, passive: true }; -// Window events -const addBlurListener = createEventHandle(BLUR, bubbleOptions); -const addFocusListener = createEventHandle(FOCUS, bubbleOptions); -// Must be capture phase because 'stopPropagation' might prevent these -// events bubbling to the document. -const addVisibilityChangeListener = createEventHandle( - VISIBILITYCHANGE, - captureOptions -); -const addKeyDownListener = createEventHandle(KEYDOWN, captureOptions); -const addPointerDownListener = createEventHandle(POINTERDOWN, captureOptions); -const addPointerMoveListener = createEventHandle(POINTERMOVE, captureOptions); -// Fallback events -const addContextMenuListener = createEventHandle(CONTEXTMENU, captureOptions); -const addMouseDownListener = createEventHandle(MOUSEDOWN, captureOptions); -const addMouseMoveListener = createEventHandle(MOUSEMOVE, captureOptions); -const addMouseUpListener = createEventHandle(MOUSEUP, captureOptions); -const addScrollListener = createEventHandle(SCROLL, captureOptions); -const addSelectiomChangeListener = createEventHandle( - SELECTIONCHANGE, - captureOptions -); -const addTouchCancelListener = createEventHandle(TOUCHCANCEL, captureOptions); -const addTouchMoveListener = createEventHandle(TOUCHMOVE, captureOptions); -const addTouchStartListener = createEventHandle(TOUCHSTART, captureOptions); - function restoreModality() { if (previousModality != null || previousActiveModality != null) { if (previousModality != null) { @@ -184,22 +158,30 @@ function onPointerish(event: any) { } if (canUseDOM) { - addBlurListener(window, onBlurWindow); - addFocusListener(window, onFocusWindow); - addKeyDownListener(document, onKeyDown); - addPointerDownListener(document, onPointerish); - addPointerMoveListener(document, onPointerish); - addVisibilityChangeListener(document, onVisibilityChange); - // fallbacks - addContextMenuListener(document, onPointerish); - addMouseDownListener(document, onPointerish); - addMouseMoveListener(document, onPointerish); - addMouseUpListener(document, onPointerish); - addTouchCancelListener(document, onPointerish); - addTouchMoveListener(document, onPointerish); - addTouchStartListener(document, onPointerish); - addSelectiomChangeListener(document, onPointerish); - addScrollListener(document, onPointerish); + // Window events + addEventListener(window, BLUR, onBlurWindow, bubbleOptions); + addEventListener(window, FOCUS, onFocusWindow, bubbleOptions); + // Must be capture phase because 'stopPropagation' might prevent these + // events bubbling to the document. + addEventListener(document, KEYDOWN, onKeyDown, captureOptions); + addEventListener( + document, + VISIBILITYCHANGE, + onVisibilityChange, + captureOptions + ); + addEventListener(document, POINTERDOWN, onPointerish, captureOptions); + addEventListener(document, POINTERMOVE, onPointerish, captureOptions); + // Fallback events + addEventListener(document, CONTEXTMENU, onPointerish, captureOptions); + addEventListener(document, MOUSEDOWN, onPointerish, captureOptions); + addEventListener(document, MOUSEMOVE, onPointerish, captureOptions); + addEventListener(document, MOUSEUP, onPointerish, captureOptions); + addEventListener(document, TOUCHCANCEL, onPointerish, captureOptions); + addEventListener(document, TOUCHMOVE, onPointerish, captureOptions); + addEventListener(document, TOUCHSTART, onPointerish, captureOptions); + addEventListener(document, SELECTIONCHANGE, onPointerish, captureOptions); + addEventListener(document, SCROLL, onPointerish, captureOptions); } function callListeners() { diff --git a/packages/react-native-web/src/modules/useEvent/index.js b/packages/react-native-web/src/modules/useEvent/index.js index 22b654463d..3d726b35a7 100644 --- a/packages/react-native-web/src/modules/useEvent/index.js +++ b/packages/react-native-web/src/modules/useEvent/index.js @@ -7,7 +7,7 @@ * @flow */ -import createEventHandle from '../createEventHandle'; +import { addEventListener } from '../addEventListener'; import useLayoutEffect from '../useLayoutEffect'; import useStable from '../useStable'; @@ -27,16 +27,16 @@ type AddListener = ( * }). */ export default function useEvent( - event: string, + eventType: string, options?: ?{ capture?: boolean, - passive?: boolean + passive?: boolean, + once?: boolean } ): AddListener { const targetListeners = useStable(() => new Map()); const addListener = useStable(() => { - const addEventListener = createEventHandle(event, options); return (target: EventTarget, callback: Callback) => { const removeTargetListener = targetListeners.get(target); if (removeTargetListener != null) { @@ -44,8 +44,14 @@ export default function useEvent( } if (callback == null) { targetListeners.delete(target); + callback = () => {}; } - const removeEventListener = addEventListener(target, callback); + const removeEventListener = addEventListener( + target, + eventType, + callback, + options + ); targetListeners.set(target, removeEventListener); return removeEventListener; };