Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update patch for NextJS & react-native-web in documentation #2659

Open
Under-Warz opened this issue Jan 2, 2025 · 0 comments
Open

Update patch for NextJS & react-native-web in documentation #2659

Under-Warz opened this issue Jan 2, 2025 · 0 comments
Assignees

Comments

@Under-Warz
Copy link

Description

Hi,

I started a fresh project with NextJS & Gluestack and the patch applied for react-native-web@0.19.13 is not working.

Problem Statement

The problem comes from an export of the render function which is the default export and not a named one.

Proposed Solution or API

diff --git a/node_modules/react-native-web/dist/cjs/exports/AppRegistry/renderApplication.js b/node_modules/react-native-web/dist/cjs/exports/AppRegistry/renderApplication.js
index 0c0cb2f..83fd94b 100644
--- a/node_modules/react-native-web/dist/cjs/exports/AppRegistry/renderApplication.js
+++ b/node_modules/react-native-web/dist/cjs/exports/AppRegistry/renderApplication.js
@@ -1,6 +1,5 @@
 "use strict";
 
-var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
 var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
 exports.__esModule = true;
 exports.default = renderApplication;
@@ -8,7 +7,7 @@ exports.getApplication = getApplication;
 var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
 var _AppContainer = _interopRequireDefault(require("./AppContainer"));
 var _invariant = _interopRequireDefault(require("fbjs/lib/invariant"));
-var _render = _interopRequireWildcard(require("../render"));
+var _render = require("../render");
 var _StyleSheet = _interopRequireDefault(require("../StyleSheet"));
 var _react = _interopRequireDefault(require("react"));
 /**
@@ -24,9 +23,8 @@ var _react = _interopRequireDefault(require("react"));
 function renderApplication(RootComponent, WrapperComponent, callback, options) {
   var shouldHydrate = options.hydrate,
     initialProps = options.initialProps,
-    mode = options.mode,
     rootTag = options.rootTag;
-  var renderFn = shouldHydrate ? mode === 'concurrent' ? _render.hydrate : _render.hydrateLegacy : mode === 'concurrent' ? _render.render : _render.default;
+  var renderFn = shouldHydrate ? _render.hydrate : _render.render;
   (0, _invariant.default)(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag);
   return renderFn(/*#__PURE__*/_react.default.createElement(_AppContainer.default, {
     WrapperComponent: WrapperComponent,
diff --git a/node_modules/react-native-web/dist/cjs/exports/render/index.js b/node_modules/react-native-web/dist/cjs/exports/render/index.js
index b41ee11..18d9b2f 100644
--- a/node_modules/react-native-web/dist/cjs/exports/render/index.js
+++ b/node_modules/react-native-web/dist/cjs/exports/render/index.js
@@ -10,15 +10,10 @@
 
 'use client';
 
-var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
 exports.__esModule = true;
-exports.default = renderLegacy;
+exports.default = render;
 exports.hydrate = hydrate;
-exports.hydrateLegacy = hydrateLegacy;
-exports.render = render;
-var _reactDom = require("react-dom");
 var _client = require("react-dom/client");
-var _unmountComponentAtNode = _interopRequireDefault(require("../unmountComponentAtNode"));
 var _dom = require("../StyleSheet/dom");
 function hydrate(element, root) {
   (0, _dom.createSheet)(root);
@@ -30,21 +25,3 @@ function render(element, root) {
   reactRoot.render(element);
   return reactRoot;
 }
\ No newline at end of file
-function hydrateLegacy(element, root, callback) {
-  (0, _dom.createSheet)(root);
-  (0, _reactDom.hydrate)(element, root, callback);
-  return {
-    unmount: function unmount() {
-      return (0, _unmountComponentAtNode.default)(root);
-    }
-  };
-}
-function renderLegacy(element, root, callback) {
-  (0, _dom.createSheet)(root);
-  (0, _reactDom.render)(element, root, callback);
-  return {
-    unmount: function unmount() {
-      return (0, _unmountComponentAtNode.default)(root);
-    }
-  };
-}
\ No newline at end of file
diff --git a/node_modules/react-native-web/dist/cjs/exports/unmountComponentAtNode/index.js b/node_modules/react-native-web/dist/cjs/exports/unmountComponentAtNode/index.js
index 3ea3964..e740204 100644
--- a/node_modules/react-native-web/dist/cjs/exports/unmountComponentAtNode/index.js
+++ b/node_modules/react-native-web/dist/cjs/exports/unmountComponentAtNode/index.js
@@ -1,8 +1,7 @@
 "use strict";
 
 exports.__esModule = true;
-exports.default = void 0;
-var _reactDom = require("react-dom");
+exports.default = unmountComponentAtNode;
 /**
  * Copyright (c) Nicolas Gallagher.
  *
@@ -11,5 +10,9 @@ var _reactDom = require("react-dom");
  *
  * 
  */
-var _default = exports.default = _reactDom.unmountComponentAtNode;
+
+function unmountComponentAtNode(rootTag) {
+  rootTag.unmount();
+  return true;
+}
 module.exports = exports.default;
\ No newline at end of file
diff --git a/node_modules/react-native-web/dist/exports/AppRegistry/renderApplication.js b/node_modules/react-native-web/dist/exports/AppRegistry/renderApplication.js
index b53dff6..c56c1dc 100644
--- a/node_modules/react-native-web/dist/exports/AppRegistry/renderApplication.js
+++ b/node_modules/react-native-web/dist/exports/AppRegistry/renderApplication.js
@@ -11,15 +11,14 @@ import _extends from "@babel/runtime/helpers/extends";
 
 import AppContainer from './AppContainer';
 import invariant from 'fbjs/lib/invariant';
-import renderLegacy, { hydrateLegacy, render, hydrate } from '../render';
+import render, { hydrate } from '../render';
 import StyleSheet from '../StyleSheet';
 import React from 'react';
 export default function renderApplication(RootComponent, WrapperComponent, callback, options) {
   var shouldHydrate = options.hydrate,
     initialProps = options.initialProps,
-    mode = options.mode,
     rootTag = options.rootTag;
-  var renderFn = shouldHydrate ? mode === 'concurrent' ? hydrate : hydrateLegacy : mode === 'concurrent' ? render : renderLegacy;
+  var renderFn = shouldHydrate ? hydrate : render;
   invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag);
   return renderFn(/*#__PURE__*/React.createElement(AppContainer, {
     WrapperComponent: WrapperComponent,
diff --git a/node_modules/react-native-web/dist/exports/AppRegistry/renderApplication.js.flow b/node_modules/react-native-web/dist/exports/AppRegistry/renderApplication.js.flow
index b9df2af..2b671ba 100644
--- a/node_modules/react-native-web/dist/exports/AppRegistry/renderApplication.js.flow
+++ b/node_modules/react-native-web/dist/exports/AppRegistry/renderApplication.js.flow
@@ -11,7 +11,7 @@
 import type { ComponentType, Node } from 'react';
 import AppContainer from './AppContainer';
 import invariant from 'fbjs/lib/invariant';
-import renderLegacy, { hydrateLegacy, render, hydrate } from '../render';
+import render, { hydrate } from '../render';
 import StyleSheet from '../StyleSheet';
 import React from 'react';
 export type Application = {
@@ -20,7 +20,6 @@ export type Application = {
 declare export default function renderApplication<Props: Object>(RootComponent: ComponentType<Props>, WrapperComponent?: ?ComponentType<*>, callback?: () => void, options: {
   hydrate: boolean,
   initialProps: Props,
-  mode: 'concurrent' | 'legacy',
   rootTag: any,
 }): Application;
 declare export function getApplication(RootComponent: ComponentType<Object>, initialProps: Object, WrapperComponent?: ?ComponentType<*>): {|
diff --git a/node_modules/react-native-web/dist/exports/render/index.js b/node_modules/react-native-web/dist/exports/render/index.js
index aa91a2a..8f9a14d 100644
--- a/node_modules/react-native-web/dist/exports/render/index.js
+++ b/node_modules/react-native-web/dist/exports/render/index.js
@@ -9,35 +9,15 @@
 
 'use client';
 
-import { hydrate as domLegacyHydrate, render as domLegacyRender } from 'react-dom';
 import { createRoot as domCreateRoot, hydrateRoot as domHydrateRoot } from 'react-dom/client';
-import unmountComponentAtNode from '../unmountComponentAtNode';
 import { createSheet } from '../StyleSheet/dom';
 export function hydrate(element, root) {
   createSheet(root);
   return domHydrateRoot(root, element);
 }
-export function render(element, root) {
+export default function render(element, root) {
   createSheet(root);
   var reactRoot = domCreateRoot(root);
   reactRoot.render(element);
   return reactRoot;
 }
\ No newline at end of file
-export function hydrateLegacy(element, root, callback) {
-  createSheet(root);
-  domLegacyHydrate(element, root, callback);
-  return {
-    unmount: function unmount() {
-      return unmountComponentAtNode(root);
-    }
-  };
-}
-export default function renderLegacy(element, root, callback) {
-  createSheet(root);
-  domLegacyRender(element, root, callback);
-  return {
-    unmount: function unmount() {
-      return unmountComponentAtNode(root);
-    }
-  };
-}
\ No newline at end of file
diff --git a/node_modules/react-native-web/dist/exports/render/index.js.flow b/node_modules/react-native-web/dist/exports/render/index.js.flow
index 1bd771e..729d57d 100644
--- a/node_modules/react-native-web/dist/exports/render/index.js.flow
+++ b/node_modules/react-native-web/dist/exports/render/index.js.flow
@@ -9,11 +9,7 @@
 
 'use client';
 
-import { hydrate as domLegacyHydrate, render as domLegacyRender } from 'react-dom';
 import { createRoot as domCreateRoot, hydrateRoot as domHydrateRoot } from 'react-dom/client';
-import unmountComponentAtNode from '../unmountComponentAtNode';
 import { createSheet } from '../StyleSheet/dom';
 declare export function hydrate(element: any, root: any): any;
-declare export function render(element: any, root: any): any;
-declare export function hydrateLegacy(element: any, root: any, callback: any): any;
-declare export default function renderLegacy(element: any, root: any, callback: any): any;
\ No newline at end of file
+declare export default function render(element: any, root: any): any;
\ No newline at end of file
diff --git a/node_modules/react-native-web/dist/exports/unmountComponentAtNode/index.js b/node_modules/react-native-web/dist/exports/unmountComponentAtNode/index.js
index 925051c..cea4dee 100644
--- a/node_modules/react-native-web/dist/exports/unmountComponentAtNode/index.js
+++ b/node_modules/react-native-web/dist/exports/unmountComponentAtNode/index.js
@@ -7,5 +7,7 @@
  * 
  */
 
-import { unmountComponentAtNode } from 'react-dom';
-export default unmountComponentAtNode;
\ No newline at end of file
+export default function unmountComponentAtNode(rootTag) {
+  rootTag.unmount();
+  return true;
+}
\ No newline at end of file
diff --git a/node_modules/react-native-web/dist/exports/unmountComponentAtNode/index.js.flow b/node_modules/react-native-web/dist/exports/unmountComponentAtNode/index.js.flow
index b950090..90ec151 100644
--- a/node_modules/react-native-web/dist/exports/unmountComponentAtNode/index.js.flow
+++ b/node_modules/react-native-web/dist/exports/unmountComponentAtNode/index.js.flow
@@ -6,6 +6,4 @@
  *
  * @noflow
  */
-
-import { unmountComponentAtNode } from 'react-dom';
-export default unmountComponentAtNode;
\ No newline at end of file
+declare export default function unmountComponentAtNode(rootTag: any): any;
\ No newline at end of file
diff --git a/node_modules/react-native-web/dist/modules/addEventListener/__tests__/index-test.js.flow b/node_modules/react-native-web/dist/modules/addEventListener/__tests__/index-test.js.flow
new file mode 100644
index 0000000..9eb6144
--- /dev/null
+++ b/node_modules/react-native-web/dist/modules/addEventListener/__tests__/index-test.js.flow
@@ -0,0 +1,191 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow strict-local
+ */
+
+import * as React from 'react';
+import { act, render } from '@testing-library/react';
+import { createEventTarget } from 'dom-event-testing-library';
+import { addEventListener } from '..';
+describe('addEventListener', () => {
+  describe('addEventListener()', () => {
+    test('event dispatched on target', () => {
+      const listener = jest.fn();
+      const targetRef = React.createRef();
+      declare function Component(): any;
+      render(<Component />);
+      const target = createEventTarget(targetRef.current);
+      act(() => {
+        target.click();
+      });
+      expect(listener).toBeCalledTimes(1);
+    });
+    test('event dispatched on parent', () => {
+      const listener = jest.fn();
+      const listenerCapture = jest.fn();
+      const targetRef = React.createRef();
+      const parentRef = React.createRef();
+      declare function Component(): any;
+      render(<Component />);
+      const parent = createEventTarget(parentRef.current);
+      act(() => {
+        parent.click();
+      });
+      expect(listener).toBeCalledTimes(0);
+      expect(listenerCapture).toBeCalledTimes(0);
+    });
+    test('event dispatched on child', () => {
+      const log = [];
+      const listener = jest.fn(() => {
+        log.push('bubble');
+      });
+      const listenerCapture = jest.fn(() => {
+        log.push('capture');
+      });
+      const targetRef = React.createRef();
+      const childRef = React.createRef();
+      declare function Component(): any;
+      render(<Component />);
+      const child = createEventTarget(childRef.current);
+      act(() => {
+        child.click();
+      });
+      expect(listenerCapture).toBeCalledTimes(1);
+      expect(listener).toBeCalledTimes(1);
+      expect(log).toEqual(['capture', 'bubble']);
+    });
+    test('event dispatched on text node', () => {
+      const listener = jest.fn();
+      const targetRef = React.createRef();
+      const childRef = React.createRef();
+      declare function Component(): any;
+      render(<Component />);
+      const text = createEventTarget(childRef.current.firstChild);
+      act(() => {
+        text.click();
+      });
+      expect(listener).toBeCalledTimes(1);
+    });
+    test('listener can be attached to document', () => {
+      const listener = jest.fn();
+      const targetRef = React.createRef();
+      declare function Component(arg0: any): any;
+      render(<Component target={document} />);
+      const target = createEventTarget(targetRef.current);
+      act(() => {
+        target.click();
+      });
+      expect(listener).toBeCalledTimes(1);
+    });
+    test('listener can be attached to window ', () => {
+      const listener = jest.fn();
+      const targetRef = React.createRef();
+      declare function Component(arg0: any): any;
+      render(<Component target={window} />);
+      const target = createEventTarget(targetRef.current);
+      act(() => {
+        target.click();
+      });
+      expect(listener).toBeCalledTimes(1);
+    });
+    test('custom event dispatched on target', () => {
+      const listener = jest.fn();
+      const targetRef = React.createRef();
+      declare function Component(): any;
+      render(<Component />);
+      act(() => {
+        const event = new CustomEvent('magic-event', {
+          bubbles: true
+        });
+        targetRef.current.dispatchEvent(event);
+      });
+      expect(listener).toBeCalledTimes(1);
+    });
+    test('listeners can be set on multiple targets simultaneously', () => {
+      const log = [];
+      const targetRef = React.createRef();
+      const parentRef = React.createRef();
+      const childRef = React.createRef();
+      const listener = jest.fn(e => {
+        log.push(['bubble', e.currentTarget.id]);
+      });
+      const listenerCapture = jest.fn(e => {
+        log.push(['capture', e.currentTarget.id]);
+      });
+      declare function Component(): any;
+      render(<Component />);
+      const child = createEventTarget(childRef.current);
+      act(() => {
+        child.click();
+      });
+      expect(listenerCapture).toBeCalledTimes(2);
+      expect(listener).toBeCalledTimes(2);
+      expect(log).toEqual([['capture', 'parent'], ['capture', 'target'], ['bubble', 'target'], ['bubble', 'parent']]);
+    });
+    test('listeners are specific to each event handle', () => {
+      const log = [];
+      const targetRef = React.createRef();
+      const childRef = React.createRef();
+      const listener = jest.fn(e => {
+        log.push(['bubble', 'target']);
+      });
+      const listenerAlt = jest.fn(e => {
+        log.push(['bubble', 'target-alt']);
+      });
+      const listenerCapture = jest.fn(e => {
+        log.push(['capture', 'target']);
+      });
+      const listenerCaptureAlt = jest.fn(e => {
+        log.push(['capture', 'target-alt']);
+      });
+      declare function Component(): any;
+      render(<Component />);
+      const child = createEventTarget(childRef.current);
+      act(() => {
+        child.click();
+      });
+      expect(listenerCapture).toBeCalledTimes(1);
+      expect(listenerCaptureAlt).toBeCalledTimes(1);
+      expect(listener).toBeCalledTimes(1);
+      expect(listenerAlt).toBeCalledTimes(1);
+      expect(log).toEqual([['capture', 'target'], ['capture', 'target-alt'], ['bubble', 'target'], ['bubble', 'target-alt']]);
+    });
+  });
+  describe('stopPropagation and stopImmediatePropagation', () => {
+    test('stopPropagation works as expected', () => {
+      const childListener = jest.fn(e => {
+        e.stopPropagation();
+      });
+      const targetListener = jest.fn();
+      const targetRef = React.createRef();
+      const childRef = React.createRef();
+      declare function Component(): any;
+      render(<Component />);
+      const child = createEventTarget(childRef.current);
+      act(() => {
+        child.click();
+      });
+      expect(childListener).toBeCalledTimes(1);
+      expect(targetListener).toBeCalledTimes(0);
+    });
+    test('stopImmediatePropagation works as expected', () => {
+      const firstListener = jest.fn(e => {
+        e.stopImmediatePropagation();
+      });
+      const secondListener = jest.fn();
+      const targetRef = React.createRef();
+      declare function Component(): any;
+      render(<Component />);
+      const target = createEventTarget(targetRef.current);
+      act(() => {
+        target.click();
+      });
+      expect(firstListener).toBeCalledTimes(1);
+      expect(secondListener).toBeCalledTimes(0);
+    });
+  });
+});
\ No newline at end of file
diff --git a/node_modules/react-native-web/dist/modules/addEventListener/__tests__/index-test.node.js.flow b/node_modules/react-native-web/dist/modules/addEventListener/__tests__/index-test.node.js.flow
new file mode 100644
index 0000000..c1805b7
--- /dev/null
+++ b/node_modules/react-native-web/dist/modules/addEventListener/__tests__/index-test.node.js.flow
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow strict-local
+ */
+
+import * as React from 'react';
+import * as ReactDOMServer from 'react-dom/server';
+import { addEventListener } from '..';
+describe('addEventListener', () => {
+  test('can render correctly using ReactDOMServer', () => {
+    const listener = jest.fn();
+    const targetRef = React.createRef();
+    declare function Component(): any;
+    const output = ReactDOMServer.renderToString(<Component />);
+    expect(output).toBe('<div></div>');
+  });
+});
\ No newline at end of file
diff --git a/node_modules/react-native-web/dist/modules/useEvent/__tests__/index-test.js.flow b/node_modules/react-native-web/dist/modules/useEvent/__tests__/index-test.js.flow
new file mode 100644
index 0000000..9b57364
--- /dev/null
+++ b/node_modules/react-native-web/dist/modules/useEvent/__tests__/index-test.js.flow
@@ -0,0 +1,247 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow strict-local
+ */
+
+import * as React from 'react';
+import { act, render } from '@testing-library/react';
+import { createEventTarget } from 'dom-event-testing-library';
+import useEvent from '..';
+describe('use-event', () => {
+  describe('setListener()', () => {
+    test('event dispatched on target', () => {
+      const listener = jest.fn();
+      const targetRef = React.createRef();
+      declare function Component(): any;
+      render(<Component />);
+      const target = createEventTarget(targetRef.current);
+      act(() => {
+        target.click();
+      });
+      expect(listener).toBeCalledTimes(1);
+    });
+    test('event dispatched on parent', () => {
+      const listener = jest.fn();
+      const listenerCapture = jest.fn();
+      const targetRef = React.createRef();
+      const parentRef = React.createRef();
+      declare function Component(): any;
+      render(<Component />);
+      const parent = createEventTarget(parentRef.current);
+      act(() => {
+        parent.click();
+      });
+      expect(listener).toBeCalledTimes(0);
+      expect(listenerCapture).toBeCalledTimes(0);
+    });
+    test('event dispatched on child', () => {
+      const log = [];
+      const listener = jest.fn(() => {
+        log.push('bubble');
+      });
+      const listenerCapture = jest.fn(() => {
+        log.push('capture');
+      });
+      const targetRef = React.createRef();
+      const childRef = React.createRef();
+      declare function Component(): any;
+      render(<Component />);
+      const child = createEventTarget(childRef.current);
+      act(() => {
+        child.click();
+      });
+      expect(listenerCapture).toBeCalledTimes(1);
+      expect(listener).toBeCalledTimes(1);
+      expect(log).toEqual(['capture', 'bubble']);
+    });
+    test('event dispatched on text node', () => {
+      const listener = jest.fn();
+      const targetRef = React.createRef();
+      const childRef = React.createRef();
+      declare function Component(): any;
+      render(<Component />);
+      const text = createEventTarget(childRef.current.firstChild);
+      act(() => {
+        text.click();
+      });
+      expect(listener).toBeCalledTimes(1);
+    });
+    test('listener can be attached to document ', () => {
+      const listener = jest.fn();
+      const targetRef = React.createRef();
+      declare function Component(arg0: any): any;
+      render(<Component target={document} />);
+      const target = createEventTarget(targetRef.current);
+      act(() => {
+        target.click();
+      });
+      expect(listener).toBeCalledTimes(1);
+    });
+    test('listener can be attached to window ', () => {
+      const listener = jest.fn();
+      const targetRef = React.createRef();
+      declare function Component(arg0: any): any;
+      render(<Component target={window} />);
+      const target = createEventTarget(targetRef.current);
+      act(() => {
+        target.click();
+      });
+      expect(listener).toBeCalledTimes(1);
+    });
+    test('listener is replaceable', () => {
+      const listener = jest.fn();
+      const listenerAlt = jest.fn();
+      const targetRef = React.createRef();
+      declare function Component(arg0: any): any;
+      const {
+        rerender
+      } = render(<Component onClick={listener} />);
+      const target = createEventTarget(targetRef.current);
+      act(() => {
+        target.click();
+      });
+      expect(listener).toBeCalledTimes(1);
+      rerender(<Component onClick={listenerAlt} />);
+      act(() => {
+        target.click();
+      });
+      expect(listener).toBeCalledTimes(1);
+      expect(listenerAlt).toBeCalledTimes(1);
+    });
+    test('listener is removed when value is null', () => {
+      const listener = jest.fn();
+      const targetRef = React.createRef();
+      declare function Component(arg0: any): any;
+      const {
+        unmount
+      } = render(<Component off={false} />);
+      const target = createEventTarget(targetRef.current);
+      act(() => {
+        target.click();
+      });
+      expect(listener).toBeCalledTimes(1);
+
+      // this should unset the listener
+      unmount();
+      listener.mockClear();
+      act(() => {
+        target.click();
+      });
+      expect(listener).toBeCalledTimes(0);
+    });
+    test('custom event dispatched on target', () => {
+      const listener = jest.fn();
+      const targetRef = React.createRef();
+      declare function Component(): any;
+      render(<Component />);
+      act(() => {
+        const event = new CustomEvent('magic-event', {
+          bubbles: true
+        });
+        targetRef.current.dispatchEvent(event);
+      });
+      expect(listener).toBeCalledTimes(1);
+    });
+    test('listeners can be set on multiple targets simultaneously', () => {
+      const log = [];
+      const targetRef = React.createRef();
+      const parentRef = React.createRef();
+      const childRef = React.createRef();
+      const listener = jest.fn(e => {
+        log.push(['bubble', e.currentTarget.id]);
+      });
+      const listenerCapture = jest.fn(e => {
+        log.push(['capture', e.currentTarget.id]);
+      });
+      declare function Component(): any;
+      render(<Component />);
+      const child = createEventTarget(childRef.current);
+      act(() => {
+        child.click();
+      });
+      expect(listenerCapture).toBeCalledTimes(2);
+      expect(listener).toBeCalledTimes(2);
+      expect(log).toEqual([['capture', 'parent'], ['capture', 'target'], ['bubble', 'target'], ['bubble', 'parent']]);
+    });
+    test('listeners are specific to each event handle', () => {
+      const log = [];
+      const targetRef = React.createRef();
+      const childRef = React.createRef();
+      const listener = jest.fn(e => {
+        log.push(['bubble', 'target']);
+      });
+      const listenerAlt = jest.fn(e => {
+        log.push(['bubble', 'target-alt']);
+      });
+      const listenerCapture = jest.fn(e => {
+        log.push(['capture', 'target']);
+      });
+      const listenerCaptureAlt = jest.fn(e => {
+        log.push(['capture', 'target-alt']);
+      });
+      declare function Component(): any;
+      render(<Component />);
+      const child = createEventTarget(childRef.current);
+      act(() => {
+        child.click();
+      });
+      expect(listenerCapture).toBeCalledTimes(1);
+      expect(listenerCaptureAlt).toBeCalledTimes(1);
+      expect(listener).toBeCalledTimes(1);
+      expect(listenerAlt).toBeCalledTimes(1);
+      expect(log).toEqual([['capture', 'target'], ['capture', 'target-alt'], ['bubble', 'target'], ['bubble', 'target-alt']]);
+    });
+  });
+  describe('cleanup', () => {
+    test('removes all listeners for given event type from targets', () => {
+      const clickListener = jest.fn();
+      declare function Component(): any;
+      const {
+        unmount
+      } = render(<Component />);
+      unmount();
+      const target = createEventTarget(document);
+      act(() => {
+        target.click();
+      });
+      expect(clickListener).toBeCalledTimes(0);
+    });
+  });
+  describe('stopPropagation and stopImmediatePropagation', () => {
+    test('stopPropagation works as expected', () => {
+      const childListener = jest.fn(e => {
+        e.stopPropagation();
+      });
+      const targetListener = jest.fn();
+      const targetRef = React.createRef();
+      const childRef = React.createRef();
+      declare function Component(): any;
+      render(<Component />);
+      const child = createEventTarget(childRef.current);
+      act(() => {
+        child.click();
+      });
+      expect(childListener).toBeCalledTimes(1);
+      expect(targetListener).toBeCalledTimes(0);
+    });
+    test('stopImmediatePropagation works as expected', () => {
+      const firstListener = jest.fn(e => {
+        e.stopImmediatePropagation();
+      });
+      const secondListener = jest.fn();
+      const targetRef = React.createRef();
+      declare function Component(): any;
+      render(<Component />);
+      const target = createEventTarget(targetRef.current);
+      act(() => {
+        target.click();
+      });
+      expect(firstListener).toBeCalledTimes(1);
+      expect(secondListener).toBeCalledTimes(0);
+    });
+  });
+});
\ No newline at end of file
diff --git a/node_modules/react-native-web/dist/modules/useStable/__tests__/index-test.js.flow b/node_modules/react-native-web/dist/modules/useStable/__tests__/index-test.js.flow
new file mode 100644
index 0000000..49edfc6
--- /dev/null
+++ b/node_modules/react-native-web/dist/modules/useStable/__tests__/index-test.js.flow
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow
+ */
+
+import * as React from 'react';
+import { render } from '@testing-library/react';
+import useStable from '..';
+describe('useStable', () => {
+  let spy = {};
+  declare var TestComponent: (arg0: any) => React.Node;
+  beforeEach(() => {
+    spy = {};
+  });
+  test('correctly sets the initial value', () => {
+    declare var initialValueCallback: () => any;
+    render(<TestComponent initialValueCallback={initialValueCallback} />);
+    expect(spy.value).toBe(5);
+  });
+  test('does not change the value', () => {
+    let counter = 0;
+    declare var initialValueCallback: () => any;
+    const {
+      rerender
+    } = render(<TestComponent initialValueCallback={initialValueCallback} />);
+    expect(spy.value).toBe(0);
+    rerender(<TestComponent initialValueCallback={initialValueCallback} />);
+    expect(spy.value).toBe(0);
+  });
+  test('only calls the callback once', () => {
+    let counter = 0;
+    declare var initialValueCallback: () => any;
+    const {
+      rerender
+    } = render(<TestComponent initialValueCallback={initialValueCallback} />);
+    expect(counter).toBe(1);
+    rerender(<TestComponent initialValueCallback={initialValueCallback} />);
+    expect(counter).toBe(1);
+  });
+  test('does not change the value if the callback initially returns null', () => {
+    let counter = 0;
+    declare var initialValueCallback: () => any;
+    const {
+      rerender
+    } = render(<TestComponent initialValueCallback={initialValueCallback} />);
+    expect(spy.value).toBe(null);
+    rerender(<TestComponent initialValueCallback={initialValueCallback} />);
+    expect(spy.value).toBe(null);
+  });
+});
\ No newline at end of file

Alternatives

No response

Additional Information

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

No branches or pull requests

2 participants