diff --git a/packages/react-dom/src/client/ReactDOMHostConfig.js b/packages/react-dom/src/client/ReactDOMHostConfig.js index d3e49e974f37..a2f2a26e7ff3 100644 --- a/packages/react-dom/src/client/ReactDOMHostConfig.js +++ b/packages/react-dom/src/client/ReactDOMHostConfig.js @@ -1172,8 +1172,8 @@ export function validateEventListenerTarget( console.warn( 'Event listener method setListener() from useEvent() hook requires the first argument to be either:' + '\n\n' + - '1. A valid DOM node that was rendered and managed by React' + - '2. The "window" object' + + '1. A valid DOM node that was rendered and managed by React\n' + + '2. The "window" object\n' + '3. The "document" object', ); } diff --git a/packages/react-dom/src/client/ReactDOMUseEvent.js b/packages/react-dom/src/client/ReactDOMUseEvent.js index 6eb2c1dff293..5c00306c58e0 100644 --- a/packages/react-dom/src/client/ReactDOMUseEvent.js +++ b/packages/react-dom/src/client/ReactDOMUseEvent.js @@ -46,7 +46,7 @@ export function useEvent( ): ReactDOMListenerMap { const dispatcher = resolveDispatcher(); let capture = false; - let passive = false; + let passive = undefined; // Undefined means to use the browser default let priority = getEventPriorityForListenerSystem((type: any)); if (options != null) { diff --git a/packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js b/packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js index 3df6dbbc926e..7dc14441a7e6 100644 --- a/packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js +++ b/packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js @@ -1318,6 +1318,55 @@ describe('DOMModernPluginEventSystem', () => { expect(log[5]).toEqual(['bubble', buttonElement]); }); + it('handle propagation of click events mixed with onClick events', () => { + const buttonRef = React.createRef(); + const divRef = React.createRef(); + const log = []; + const onClick = jest.fn(e => log.push(['bubble', e.currentTarget])); + const onClickCapture = jest.fn(e => + log.push(['capture', e.currentTarget]), + ); + + function Test() { + const click = ReactDOM.unstable_useEvent('click'); + const clickCapture = ReactDOM.unstable_useEvent('click', { + capture: true, + }); + + React.useEffect(() => { + click.setListener(buttonRef.current, onClick); + clickCapture.setListener(buttonRef.current, onClickCapture); + }); + + return ( + + ); + } + + ReactDOM.render(, container); + Scheduler.unstable_flushAll(); + + let buttonElement = buttonRef.current; + dispatchClickEvent(buttonElement); + expect(onClick).toHaveBeenCalledTimes(1); + expect(onClickCapture).toHaveBeenCalledTimes(1); + expect(log[0]).toEqual(['capture', buttonElement]); + expect(log[1]).toEqual(['bubble', buttonElement]); + + let divElement = divRef.current; + dispatchClickEvent(divElement); + expect(onClick).toHaveBeenCalledTimes(3); + expect(onClickCapture).toHaveBeenCalledTimes(3); + expect(log[2]).toEqual(['capture', buttonElement]); + expect(log[3]).toEqual(['capture', divElement]); + expect(log[4]).toEqual(['bubble', divElement]); + expect(log[5]).toEqual(['bubble', buttonElement]); + }); + it('should correctly work for a basic "click" listener on the outer target', () => { const log = []; const clickEvent = jest.fn(event => { diff --git a/packages/shared/ReactDOMTypes.js b/packages/shared/ReactDOMTypes.js index fbad9e5e5d3e..9c76e7675ab2 100644 --- a/packages/shared/ReactDOMTypes.js +++ b/packages/shared/ReactDOMTypes.js @@ -78,7 +78,7 @@ export type ReactDOMResponderContext = { export type ReactDOMListenerEvent = {| capture: boolean, - passive: boolean, + passive: void | boolean, priority: EventPriority, type: string, |};