@samitouri / QOS-React / commits / a8a83f7a59

Removes the react-interactions project which is unused (#28799)

Removes the react-interactions project which is unused This project uses `unstable_createEventHandle` which is being removed from React in version 19

Josh Story committed Apr 10, 2024 at 09:18 UTC a8a83f7a5996b86f3901d5dc505b13506dd12caf
16 files changed -1549
packages/react-interactions/README.md deleted
-4
@@ -1,4 +0,0 @@
1 -# `react-interactions`
2 -
3 -This package is experimental. It is intended for use with the experimental React
4 -flags for internal testing.
\ No newline at end of file
packages/react-interactions/events/focus.js deleted
-10
@@ -1,10 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -export * from './src/dom/create-event-handle/Focus';
packages/react-interactions/events/src/dom/create-event-handle/Focus.js deleted
-400
@@ -1,400 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -import * as React from 'react';
11 -import useEvent from './useEvent';
12 -
13 -const {useCallback, useEffect, useLayoutEffect, useRef} = React;
14 -
15 -type FocusEvent = SyntheticEvent<EventTarget>;
16 -
17 -type UseFocusOptions = {
18 - disabled?: boolean,
19 - onBlur?: ?(FocusEvent) => void,
20 - onFocus?: ?(FocusEvent) => void,
21 - onFocusChange?: ?(boolean) => void,
22 - onFocusVisibleChange?: ?(boolean) => void,
23 -};
24 -
25 -type UseFocusWithinOptions = {
26 - disabled?: boolean,
27 - onAfterBlurWithin?: FocusEvent => void,
28 - onBeforeBlurWithin?: FocusEvent => void,
29 - onBlurWithin?: FocusEvent => void,
30 - onFocusWithin?: FocusEvent => void,
31 - onFocusWithinChange?: boolean => void,
32 - onFocusWithinVisibleChange?: boolean => void,
33 -};
34 -
35 -const isMac =
36 - typeof window !== 'undefined' && window.navigator != null
37 - ? /^Mac/.test(window.navigator.platform)
38 - : false;
39 -
40 -const hasPointerEvents =
41 - typeof window !== 'undefined' && window.PointerEvent != null;
42 -
43 -const globalFocusVisibleEvents = hasPointerEvents
44 - ? ['keydown', 'pointermove', 'pointerdown', 'pointerup']
45 - : [
46 - 'keydown',
47 - 'mousedown',
48 - 'mousemove',
49 - 'mouseup',
50 - 'touchmove',
51 - 'touchstart',
52 - 'touchend',
53 - ];
54 -
55 -// Global state for tracking focus visible and emulation of mouse
56 -let isGlobalFocusVisible = true;
57 -let hasTrackedGlobalFocusVisible = false;
58 -
59 -function trackGlobalFocusVisible() {
60 - globalFocusVisibleEvents.forEach(type => {
61 - window.addEventListener(type, handleGlobalFocusVisibleEvent, true);
62 - });
63 -}
64 -
65 -function isValidKey(nativeEvent: KeyboardEvent): boolean {
66 - const {metaKey, altKey, ctrlKey} = nativeEvent;
67 - return !(metaKey || (!isMac && altKey) || ctrlKey);
68 -}
69 -
70 -function isTextInput(nativeEvent: KeyboardEvent): boolean {
71 - const {key, target} = nativeEvent;
72 - if (key === 'Tab' || key === 'Escape') {
73 - return false;
74 - }
75 - const {isContentEditable, tagName} = (target: any);
76 - return tagName === 'INPUT' || tagName === 'TEXTAREA' || isContentEditable;
77 -}
78 -
79 -function handleGlobalFocusVisibleEvent(
80 - nativeEvent: MouseEvent | TouchEvent | KeyboardEvent,
81 -): void {
82 - if (nativeEvent.type === 'keydown') {
83 - if (isValidKey(((nativeEvent: any): KeyboardEvent))) {
84 - isGlobalFocusVisible = true;
85 - }
86 - } else {
87 - const nodeName = (nativeEvent.target: any).nodeName;
88 - // Safari calls mousemove/pointermove events when you tab out of the active
89 - // Safari frame.
90 - if (nodeName === 'HTML') {
91 - return;
92 - }
93 - // Handle all the other mouse/touch/pointer events
94 - isGlobalFocusVisible = false;
95 - }
96 -}
97 -
98 -function handleFocusVisibleTargetEvents(
99 - event: SyntheticEvent<EventTarget>,
100 - callback: boolean => void,
101 -): void {
102 - if (event.type === 'keydown') {
103 - const {nativeEvent} = (event: any);
104 - if (isValidKey(nativeEvent) && !isTextInput(nativeEvent)) {
105 - callback(true);
106 - }
107 - } else {
108 - callback(false);
109 - }
110 -}
111 -
112 -function isRelatedTargetWithin(
113 - focusWithinTarget: Object,
114 - relatedTarget: null | EventTarget,
115 -): boolean {
116 - if (relatedTarget == null) {
117 - return false;
118 - }
119 - // As the focusWithinTarget can be a Scope Instance (experimental API),
120 - // we need to use the containsNode() method. Otherwise, focusWithinTarget
121 - // must be a Node, which means we can use the contains() method.
122 - return typeof focusWithinTarget.containsNode === 'function'
123 - ? focusWithinTarget.containsNode(relatedTarget)
124 - : focusWithinTarget.contains(relatedTarget);
125 -}
126 -
127 -function setFocusVisibleListeners(
128 - // $FlowFixMe[missing-local-annot]
129 - focusVisibleHandles,
130 - focusTarget: EventTarget,
131 - callback: boolean => void,
132 -) {
133 - focusVisibleHandles.forEach(focusVisibleHandle => {
134 - focusVisibleHandle.setListener(focusTarget, event =>
135 - handleFocusVisibleTargetEvents(event, callback),
136 - );
137 - });
138 -}
139 -
140 -function useFocusVisibleInputHandles() {
141 - return [
142 - useEvent('mousedown'),
143 - useEvent(hasPointerEvents ? 'pointerdown' : 'touchstart'),
144 - useEvent('keydown'),
145 - ];
146 -}
147 -
148 -function useFocusLifecycles() {
149 - useEffect(() => {
150 - if (!hasTrackedGlobalFocusVisible) {
151 - hasTrackedGlobalFocusVisible = true;
152 - trackGlobalFocusVisible();
153 - }
154 - }, []);
155 -}
156 -
157 -export function useFocus(
158 - focusTargetRef: {current: null | Node},
159 - {
160 - disabled,
161 - onBlur,
162 - onFocus,
163 - onFocusChange,
164 - onFocusVisibleChange,
165 - }: UseFocusOptions,
166 -): void {
167 - // Setup controlled state for this useFocus hook
168 - const stateRef = useRef<null | {
169 - isFocused: boolean,
170 - isFocusVisible: boolean,
171 - }>({isFocused: false, isFocusVisible: false});
172 - const focusHandle = useEvent('focusin');
173 - const blurHandle = useEvent('focusout');
174 - const focusVisibleHandles = useFocusVisibleInputHandles();
175 -
176 - useLayoutEffect(() => {
177 - const focusTarget = focusTargetRef.current;
178 - const state = stateRef.current;
179 -
180 - if (focusTarget !== null && state !== null && focusTarget.nodeType === 1) {
181 - // Handle focus visible
182 - setFocusVisibleListeners(
183 - focusVisibleHandles,
184 - focusTarget,
185 - isFocusVisible => {
186 - if (state.isFocused && state.isFocusVisible !== isFocusVisible) {
187 - state.isFocusVisible = isFocusVisible;
188 - if (onFocusVisibleChange) {
189 - onFocusVisibleChange(isFocusVisible);
190 - }
191 - }
192 - },
193 - );
194 -
195 - // Handle focus
196 - focusHandle.setListener(focusTarget, (event: FocusEvent) => {
197 - if (disabled === true) {
198 - return;
199 - }
200 - if (!state.isFocused && focusTarget === event.target) {
201 - state.isFocused = true;
202 - state.isFocusVisible = isGlobalFocusVisible;
203 - if (onFocus) {
204 - onFocus(event);
205 - }
206 - if (onFocusChange) {
207 - onFocusChange(true);
208 - }
209 - if (state.isFocusVisible && onFocusVisibleChange) {
210 - onFocusVisibleChange(true);
211 - }
212 - }
213 - });
214 -
215 - // Handle blur
216 - blurHandle.setListener(focusTarget, (event: FocusEvent) => {
217 - if (disabled === true) {
218 - return;
219 - }
220 - if (state.isFocused) {
221 - state.isFocused = false;
222 - state.isFocusVisible = isGlobalFocusVisible;
223 - if (onBlur) {
224 - onBlur(event);
225 - }
226 - if (onFocusChange) {
227 - onFocusChange(false);
228 - }
229 - if (state.isFocusVisible && onFocusVisibleChange) {
230 - onFocusVisibleChange(false);
231 - }
232 - }
233 - });
234 - }
235 - }, [
236 - blurHandle,
237 - disabled,
238 - focusHandle,
239 - focusTargetRef,
240 - focusVisibleHandles,
241 - onBlur,
242 - onFocus,
243 - onFocusChange,
244 - onFocusVisibleChange,
245 - ]);
246 -
247 - // Mount/Unmount logic
248 - useFocusLifecycles();
249 -}
250 -
251 -export function useFocusWithin<T>(
252 - focusWithinTargetRef:
253 - | {current: null | T}
254 - | ((focusWithinTarget: null | T) => void),
255 - {
256 - disabled,
257 - onAfterBlurWithin,
258 - onBeforeBlurWithin,
259 - onBlurWithin,
260 - onFocusWithin,
261 - onFocusWithinChange,
262 - onFocusWithinVisibleChange,
263 - }: UseFocusWithinOptions,
264 -): (focusWithinTarget: null | T) => void {
265 - // Setup controlled state for this useFocus hook
266 - const stateRef = useRef<null | {
267 - isFocused: boolean,
268 - isFocusVisible: boolean,
269 - }>({isFocused: false, isFocusVisible: false});
270 - const focusHandle = useEvent('focusin');
271 - const blurHandle = useEvent('focusout');
272 - const afterBlurHandle = useEvent('afterblur');
273 - const beforeBlurHandle = useEvent('beforeblur');
274 - const focusVisibleHandles = useFocusVisibleInputHandles();
275 -
276 - const useFocusWithinRef = useCallback(
277 - (focusWithinTarget: null | T) => {
278 - // Handle the incoming focusTargetRef. It can be either a function ref
279 - // or an object ref.
280 - if (typeof focusWithinTargetRef === 'function') {
281 - focusWithinTargetRef(focusWithinTarget);
282 - } else {
283 - focusWithinTargetRef.current = focusWithinTarget;
284 - }
285 - const state = stateRef.current;
286 -
287 - if (focusWithinTarget !== null && state !== null) {
288 - // Handle focus visible
289 - setFocusVisibleListeners(
290 - focusVisibleHandles,
291 - // $FlowFixMe[incompatible-call] focusWithinTarget is not null here
292 - focusWithinTarget,
293 - isFocusVisible => {
294 - if (state.isFocused && state.isFocusVisible !== isFocusVisible) {
295 - state.isFocusVisible = isFocusVisible;
296 - if (onFocusWithinVisibleChange) {
297 - onFocusWithinVisibleChange(isFocusVisible);
298 - }
299 - }
300 - },
301 - );
302 -
303 - // Handle focus
304 - // $FlowFixMe[incompatible-call] focusWithinTarget is not null here
305 - focusHandle.setListener(focusWithinTarget, (event: FocusEvent) => {
306 - if (disabled) {
307 - return;
308 - }
309 - if (!state.isFocused) {
310 - state.isFocused = true;
311 - state.isFocusVisible = isGlobalFocusVisible;
312 - if (onFocusWithinChange) {
313 - onFocusWithinChange(true);
314 - }
315 - if (state.isFocusVisible && onFocusWithinVisibleChange) {
316 - onFocusWithinVisibleChange(true);
317 - }
318 - }
319 - if (!state.isFocusVisible && isGlobalFocusVisible) {
320 - state.isFocusVisible = isGlobalFocusVisible;
321 - if (onFocusWithinVisibleChange) {
322 - onFocusWithinVisibleChange(true);
323 - }
324 - }
325 - if (onFocusWithin) {
326 - onFocusWithin(event);
327 - }
328 - });
329 -
330 - // Handle blur
331 - // $FlowFixMe[incompatible-call] focusWithinTarget is not null here
332 - blurHandle.setListener(focusWithinTarget, (event: FocusEvent) => {
333 - if (disabled) {
334 - return;
335 - }
336 - const {relatedTarget} = (event.nativeEvent: any);
337 -
338 - if (
339 - state.isFocused &&
340 - !isRelatedTargetWithin(focusWithinTarget, relatedTarget)
341 - ) {
342 - state.isFocused = false;
343 - if (onFocusWithinChange) {
344 - onFocusWithinChange(false);
345 - }
346 - if (state.isFocusVisible && onFocusWithinVisibleChange) {
347 - onFocusWithinVisibleChange(false);
348 - }
349 - if (onBlurWithin) {
350 - onBlurWithin(event);
351 - }
352 - }
353 - });
354 -
355 - // Handle before blur. This is a special
356 - // React provided event.
357 - // $FlowFixMe[incompatible-call] focusWithinTarget is not null here
358 - beforeBlurHandle.setListener(focusWithinTarget, (event: FocusEvent) => {
359 - if (disabled) {
360 - return;
361 - }
362 - if (onBeforeBlurWithin) {
363 - onBeforeBlurWithin(event);
364 - // Add an "afterblur" listener on document. This is a special
365 - // React provided event.
366 - afterBlurHandle.setListener(
367 - document,
368 - (afterBlurEvent: FocusEvent) => {
369 - if (onAfterBlurWithin) {
370 - onAfterBlurWithin(afterBlurEvent);
371 - }
372 - // Clear listener on document
373 - afterBlurHandle.setListener(document, null);
374 - },
375 - );
376 - }
377 - });
378 - }
379 - },
380 - [
381 - afterBlurHandle,
382 - beforeBlurHandle,
383 - blurHandle,
384 - disabled,
385 - focusHandle,
386 - focusWithinTargetRef,
387 - onAfterBlurWithin,
388 - onBeforeBlurWithin,
389 - onBlurWithin,
390 - onFocusWithin,
391 - onFocusWithinChange,
392 - onFocusWithinVisibleChange,
393 - ],
394 - );
395 -
396 - // Mount/Unmount logic
397 - useFocusLifecycles();
398 -
399 - return useFocusWithinRef;
400 -}
packages/react-interactions/events/src/dom/create-event-handle/__tests__/useFocus-test.internal.js deleted
-335
@@ -1,335 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -import {createEventTarget, setPointerEvent} from 'dom-event-testing-library';
13 -
14 -let React;
15 -let ReactFeatureFlags;
16 -let ReactDOMClient;
17 -let useFocus;
18 -let act;
19 -
20 -function initializeModules(hasPointerEvents) {
21 - setPointerEvent(hasPointerEvents);
22 - jest.resetModules();
23 - ReactFeatureFlags = require('shared/ReactFeatureFlags');
24 - ReactFeatureFlags.enableCreateEventHandleAPI = true;
25 - React = require('react');
26 - ReactDOMClient = require('react-dom/client');
27 - act = require('internal-test-utils').act;
28 - // TODO: This import throws outside of experimental mode. Figure out better
29 - // strategy for gated imports.
30 - if (__EXPERIMENTAL__ || global.__WWW__) {
31 - useFocus = require('react-interactions/events/focus').useFocus;
32 - }
33 -}
34 -
35 -const forcePointerEvents = true;
36 -const table = [[forcePointerEvents], [!forcePointerEvents]];
37 -
38 -describe.each(table)(`useFocus hasPointerEvents=%s`, hasPointerEvents => {
39 - let container;
40 -
41 - beforeEach(() => {
42 - initializeModules(hasPointerEvents);
43 - container = document.createElement('div');
44 - document.body.appendChild(container);
45 - });
46 -
47 - afterEach(() => {
48 - document.body.removeChild(container);
49 - container = null;
50 - });
51 -
52 - describe('disabled', () => {
53 - let onBlur, onFocus, ref;
54 -
55 - const componentInit = async () => {
56 - onBlur = jest.fn();
57 - onFocus = jest.fn();
58 - ref = React.createRef();
59 - const Component = () => {
60 - useFocus(ref, {
61 - disabled: true,
62 - onBlur,
63 - onFocus,
64 - });
65 - return <div ref={ref} />;
66 - };
67 - const root = ReactDOMClient.createRoot(container);
68 - await act(() => {
69 - root.render(<Component />);
70 - });
71 - };
72 -
73 - // @gate www
74 - it('does not call callbacks', async () => {
75 - await componentInit();
76 - const target = createEventTarget(ref.current);
77 - target.focus();
78 - target.blur();
79 - expect(onFocus).not.toBeCalled();
80 - expect(onBlur).not.toBeCalled();
81 - });
82 - });
83 -
84 - describe('onBlur', () => {
85 - let onBlur, ref;
86 -
87 - const componentInit = async () => {
88 - onBlur = jest.fn();
89 - ref = React.createRef();
90 - const Component = () => {
91 - useFocus(ref, {
92 - onBlur,
93 - });
94 - return <div ref={ref} />;
95 - };
96 - const root = ReactDOMClient.createRoot(container);
97 - await act(() => {
98 - root.render(<Component />);
99 - });
100 - };
101 -
102 - // @gate www
103 - it('is called after "blur" event', async () => {
104 - await componentInit();
105 - const target = createEventTarget(ref.current);
106 - target.focus();
107 - target.blur();
108 - expect(onBlur).toHaveBeenCalledTimes(1);
109 - });
110 - });
111 -
112 - describe('onFocus', () => {
113 - let onFocus, ref, innerRef;
114 -
115 - const componentInit = async () => {
116 - onFocus = jest.fn();
117 - ref = React.createRef();
118 - innerRef = React.createRef();
119 - const Component = () => {
120 - useFocus(ref, {
121 - onFocus,
122 - });
123 - return (
124 - <div ref={ref}>
125 - <a ref={innerRef} />
126 - </div>
127 - );
128 - };
129 - const root = ReactDOMClient.createRoot(container);
130 - await act(() => {
131 - root.render(<Component />);
132 - });
133 - };
134 -
135 - // @gate www
136 - it('is called after "focus" event', async () => {
137 - await componentInit();
138 - const target = createEventTarget(ref.current);
139 - target.focus();
140 - expect(onFocus).toHaveBeenCalledTimes(1);
141 - });
142 -
143 - // @gate www
144 - it('is not called if descendants of target receive focus', async () => {
145 - await componentInit();
146 - const target = createEventTarget(innerRef.current);
147 - target.focus();
148 - expect(onFocus).not.toBeCalled();
149 - });
150 - });
151 -
152 - describe('onFocusChange', () => {
153 - let onFocusChange, ref, innerRef;
154 -
155 - const componentInit = async () => {
156 - onFocusChange = jest.fn();
157 - ref = React.createRef();
158 - innerRef = React.createRef();
159 - const Component = () => {
160 - useFocus(ref, {
161 - onFocusChange,
162 - });
163 - return (
164 - <div ref={ref}>
165 - <div ref={innerRef} />
166 - </div>
167 - );
168 - };
169 - const root = ReactDOMClient.createRoot(container);
170 - await act(() => {
171 - root.render(<Component />);
172 - });
173 - };
174 -
175 - // @gate www
176 - it('is called after "blur" and "focus" events', async () => {
177 - await componentInit();
178 - const target = createEventTarget(ref.current);
179 - target.focus();
180 - expect(onFocusChange).toHaveBeenCalledTimes(1);
181 - expect(onFocusChange).toHaveBeenCalledWith(true);
182 - target.blur();
183 - expect(onFocusChange).toHaveBeenCalledTimes(2);
184 - expect(onFocusChange).toHaveBeenCalledWith(false);
185 - });
186 -
187 - // @gate www
188 - it('is not called after "blur" and "focus" events on descendants', async () => {
189 - await componentInit();
190 - const target = createEventTarget(innerRef.current);
191 - target.focus();
192 - expect(onFocusChange).toHaveBeenCalledTimes(0);
193 - target.blur();
194 - expect(onFocusChange).toHaveBeenCalledTimes(0);
195 - });
196 - });
197 -
198 - describe('onFocusVisibleChange', () => {
199 - let onFocusVisibleChange, ref, innerRef;
200 -
201 - const componentInit = async () => {
202 - onFocusVisibleChange = jest.fn();
203 - ref = React.createRef();
204 - innerRef = React.createRef();
205 - const Component = () => {
206 - useFocus(ref, {
207 - onFocusVisibleChange,
208 - });
209 - return (
210 - <div ref={ref}>
211 - <div ref={innerRef} />
212 - </div>
213 - );
214 - };
215 - const root = ReactDOMClient.createRoot(container);
216 - await act(() => {
217 - root.render(<Component />);
218 - });
219 - };
220 -
221 - // @gate www
222 - it('is called after "focus" and "blur" if keyboard navigation is active', async () => {
223 - await componentInit();
224 - const target = createEventTarget(ref.current);
225 - const containerTarget = createEventTarget(container);
226 - // use keyboard first
227 - containerTarget.keydown({key: 'Tab'});
228 - target.focus();
229 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(1);
230 - expect(onFocusVisibleChange).toHaveBeenCalledWith(true);
231 - target.blur({relatedTarget: container});
232 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(2);
233 - expect(onFocusVisibleChange).toHaveBeenCalledWith(false);
234 - });
235 -
236 - // @gate www
237 - it('is called if non-keyboard event is dispatched on target previously focused with keyboard', async () => {
238 - await componentInit();
239 - const target = createEventTarget(ref.current);
240 - const containerTarget = createEventTarget(container);
241 - // use keyboard first
242 - containerTarget.keydown({key: 'Tab'});
243 - target.focus();
244 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(1);
245 - expect(onFocusVisibleChange).toHaveBeenCalledWith(true);
246 - // then use pointer on the target, focus should no longer be visible
247 - target.pointerdown();
248 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(2);
249 - expect(onFocusVisibleChange).toHaveBeenCalledWith(false);
250 - // onFocusVisibleChange should not be called again
251 - target.blur({relatedTarget: container});
252 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(2);
253 - });
254 -
255 - // @gate www
256 - it('is not called after "focus" and "blur" events without keyboard', async () => {
257 - await componentInit();
258 - const target = createEventTarget(ref.current);
259 - const containerTarget = createEventTarget(container);
260 - target.pointerdown();
261 - target.pointerup();
262 - containerTarget.pointerdown();
263 - target.blur({relatedTarget: container});
264 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(0);
265 - });
266 -
267 - // @gate www
268 - it('is not called after "blur" and "focus" events on descendants', async () => {
269 - await componentInit();
270 - const innerTarget = createEventTarget(innerRef.current);
271 - const containerTarget = createEventTarget(container);
272 - containerTarget.keydown({key: 'Tab'});
273 - innerTarget.focus();
274 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(0);
275 - innerTarget.blur({relatedTarget: container});
276 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(0);
277 - });
278 - });
279 -
280 - describe('nested Focus components', () => {
281 - // @gate www
282 - it('propagates events in the correct order', async () => {
283 - const events = [];
284 - const innerRef = React.createRef();
285 - const outerRef = React.createRef();
286 - const createEventHandler = msg => () => {
287 - events.push(msg);
288 - };
289 -
290 - const Inner = () => {
291 - useFocus(innerRef, {
292 - onBlur: createEventHandler('inner: onBlur'),
293 - onFocus: createEventHandler('inner: onFocus'),
294 - onFocusChange: createEventHandler('inner: onFocusChange'),
295 - });
296 - return <div ref={innerRef} />;
297 - };
298 -
299 - const Outer = () => {
300 - useFocus(outerRef, {
301 - onBlur: createEventHandler('outer: onBlur'),
302 - onFocus: createEventHandler('outer: onFocus'),
303 - onFocusChange: createEventHandler('outer: onFocusChange'),
304 - });
305 - return (
306 - <div ref={outerRef}>
307 - <Inner />
308 - </div>
309 - );
310 - };
311 -
312 - const root = ReactDOMClient.createRoot(container);
313 - await act(() => {
314 - root.render(<Outer />);
315 - });
316 - const innerTarget = createEventTarget(innerRef.current);
317 - const outerTarget = createEventTarget(outerRef.current);
318 -
319 - outerTarget.focus();
320 - outerTarget.blur();
321 - innerTarget.focus();
322 - innerTarget.blur();
323 - expect(events).toEqual([
324 - 'outer: onFocus',
325 - 'outer: onFocusChange',
326 - 'outer: onBlur',
327 - 'outer: onFocusChange',
328 - 'inner: onFocus',
329 - 'inner: onFocusChange',
330 - 'inner: onBlur',
331 - 'inner: onFocusChange',
332 - ]);
333 - });
334 - });
335 -});
packages/react-interactions/events/src/dom/create-event-handle/__tests__/useFocusWithin-test.internal.js deleted
-626
@@ -1,626 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -import {createEventTarget, setPointerEvent} from 'dom-event-testing-library';
13 -
14 -let React;
15 -let ReactFeatureFlags;
16 -let ReactDOMClient;
17 -let useFocusWithin;
18 -let act;
19 -
20 -function initializeModules(hasPointerEvents) {
21 - setPointerEvent(hasPointerEvents);
22 - jest.resetModules();
23 - ReactFeatureFlags = require('shared/ReactFeatureFlags');
24 - ReactFeatureFlags.enableScopeAPI = true;
25 - ReactFeatureFlags.enableCreateEventHandleAPI = true;
26 - React = require('react');
27 - ReactDOMClient = require('react-dom/client');
28 - act = require('internal-test-utils').act;
29 -
30 - // TODO: This import throws outside of experimental mode. Figure out better
31 - // strategy for gated imports.
32 - if (__EXPERIMENTAL__ || global.__WWW__) {
33 - useFocusWithin = require('react-interactions/events/focus').useFocusWithin;
34 - }
35 -}
36 -
37 -const forcePointerEvents = true;
38 -const table = [[forcePointerEvents], [!forcePointerEvents]];
39 -
40 -describe.each(table)(`useFocus`, hasPointerEvents => {
41 - let container;
42 - let container2;
43 - let root;
44 -
45 - beforeEach(() => {
46 - initializeModules(hasPointerEvents);
47 - container = document.createElement('div');
48 - document.body.appendChild(container);
49 - container2 = document.createElement('div');
50 - document.body.appendChild(container2);
51 - root = ReactDOMClient.createRoot(container);
52 - });
53 -
54 - afterEach(async () => {
55 - await act(() => {
56 - root.render(null);
57 - });
58 -
59 - document.body.removeChild(container);
60 - document.body.removeChild(container2);
61 - container = null;
62 - container2 = null;
63 - });
64 -
65 - describe('disabled', () => {
66 - let onFocusWithinChange, onFocusWithinVisibleChange, ref;
67 -
68 - const componentInit = async () => {
69 - onFocusWithinChange = jest.fn();
70 - onFocusWithinVisibleChange = jest.fn();
71 - ref = React.createRef();
72 - const Component = () => {
73 - const focusWithinRef = useFocusWithin(ref, {
74 - disabled: true,
75 - onFocusWithinChange,
76 - onFocusWithinVisibleChange,
77 - });
78 - return <div ref={focusWithinRef} />;
79 - };
80 - await act(() => {
81 - root.render(<Component />);
82 - });
83 - };
84 -
85 - // @gate www
86 - it('prevents custom events being dispatched', async () => {
87 - await componentInit();
88 - const target = createEventTarget(ref.current);
89 - target.focus();
90 - target.blur();
91 - expect(onFocusWithinChange).not.toBeCalled();
92 - expect(onFocusWithinVisibleChange).not.toBeCalled();
93 - });
94 - });
95 -
96 - describe('onFocusWithinChange', () => {
97 - let onFocusWithinChange, ref, innerRef, innerRef2;
98 -
99 - const Component = ({show}) => {
100 - const focusWithinRef = useFocusWithin(ref, {
101 - onFocusWithinChange,
102 - });
103 - return (
104 - <div ref={focusWithinRef}>
105 - {show && <input ref={innerRef} />}
106 - <div ref={innerRef2} />
107 - </div>
108 - );
109 - };
110 -
111 - const componentInit = async () => {
112 - onFocusWithinChange = jest.fn();
113 - ref = React.createRef();
114 - innerRef = React.createRef();
115 - innerRef2 = React.createRef();
116 - await act(() => {
117 - root.render(<Component show={true} />);
118 - });
119 - };
120 -
121 - // @gate www
122 - it('is called after "blur" and "focus" events on focus target', async () => {
123 - await componentInit();
124 - const target = createEventTarget(ref.current);
125 - target.focus();
126 - expect(onFocusWithinChange).toHaveBeenCalledTimes(1);
127 - expect(onFocusWithinChange).toHaveBeenCalledWith(true);
128 - target.blur({relatedTarget: container});
129 - expect(onFocusWithinChange).toHaveBeenCalledTimes(2);
130 - expect(onFocusWithinChange).toHaveBeenCalledWith(false);
131 - });
132 -
133 - // @gate www
134 - it('is called after "blur" and "focus" events on descendants', async () => {
135 - await componentInit();
136 - const target = createEventTarget(innerRef.current);
137 - target.focus();
138 - expect(onFocusWithinChange).toHaveBeenCalledTimes(1);
139 - expect(onFocusWithinChange).toHaveBeenCalledWith(true);
140 - target.blur({relatedTarget: container});
141 - expect(onFocusWithinChange).toHaveBeenCalledTimes(2);
142 - expect(onFocusWithinChange).toHaveBeenCalledWith(false);
143 - });
144 -
145 - // @gate www
146 - it('is only called once when focus moves within and outside the subtree', async () => {
147 - await componentInit();
148 - const node = ref.current;
149 - const innerNode1 = innerRef.current;
150 - const innerNode2 = innerRef.current;
151 - const target = createEventTarget(node);
152 - const innerTarget1 = createEventTarget(innerNode1);
153 - const innerTarget2 = createEventTarget(innerNode2);
154 -
155 - // focus shifts into subtree
156 - innerTarget1.focus();
157 - expect(onFocusWithinChange).toHaveBeenCalledTimes(1);
158 - expect(onFocusWithinChange).toHaveBeenCalledWith(true);
159 - // focus moves around subtree
160 - innerTarget1.blur({relatedTarget: innerNode2});
161 - innerTarget2.focus();
162 - innerTarget2.blur({relatedTarget: node});
163 - target.focus();
164 - target.blur({relatedTarget: innerNode1});
165 - expect(onFocusWithinChange).toHaveBeenCalledTimes(1);
166 - // focus shifts outside subtree
167 - innerTarget1.blur({relatedTarget: container});
168 - expect(onFocusWithinChange).toHaveBeenCalledTimes(2);
169 - expect(onFocusWithinChange).toHaveBeenCalledWith(false);
170 - });
171 - });
172 -
173 - describe('onFocusWithinVisibleChange', () => {
174 - let onFocusWithinVisibleChange, ref, innerRef, innerRef2;
175 -
176 - const Component = ({show}) => {
177 - const focusWithinRef = useFocusWithin(ref, {
178 - onFocusWithinVisibleChange,
179 - });
180 - return (
181 - <div ref={focusWithinRef}>
182 - {show && <input ref={innerRef} />}
183 - <div ref={innerRef2} />
184 - </div>
185 - );
186 - };
187 -
188 - const componentInit = async () => {
189 - onFocusWithinVisibleChange = jest.fn();
190 - ref = React.createRef();
191 - innerRef = React.createRef();
192 - innerRef2 = React.createRef();
193 - await act(() => {
194 - root.render(<Component show={true} />);
195 - });
196 - };
197 -
198 - // @gate www
199 - it('is called after "focus" and "blur" on focus target if keyboard was used', async () => {
200 - await componentInit();
201 - const target = createEventTarget(ref.current);
202 - const containerTarget = createEventTarget(container);
203 - // use keyboard first
204 - containerTarget.keydown({key: 'Tab'});
205 - target.focus();
206 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1);
207 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true);
208 - target.blur({relatedTarget: container});
209 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(2);
210 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false);
211 - });
212 -
213 - // @gate www
214 - it('is called after "focus" and "blur" on descendants if keyboard was used', async () => {
215 - await componentInit();
216 - const innerTarget = createEventTarget(innerRef.current);
217 - const containerTarget = createEventTarget(container);
218 - // use keyboard first
219 - containerTarget.keydown({key: 'Tab'});
220 - innerTarget.focus();
221 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1);
222 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true);
223 - innerTarget.blur({relatedTarget: container});
224 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(2);
225 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false);
226 - });
227 -
228 - // @gate www
229 - it('is called if non-keyboard event is dispatched on target previously focused with keyboard', async () => {
230 - await componentInit();
231 - const node = ref.current;
232 - const innerNode1 = innerRef.current;
233 - const innerNode2 = innerRef2.current;
234 -
235 - const target = createEventTarget(node);
236 - const innerTarget1 = createEventTarget(innerNode1);
237 - const innerTarget2 = createEventTarget(innerNode2);
238 - // use keyboard first
239 - target.focus();
240 - target.keydown({key: 'Tab'});
241 - target.blur({relatedTarget: innerNode1});
242 - innerTarget1.focus();
243 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1);
244 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true);
245 - // then use pointer on the next target, focus should no longer be visible
246 - innerTarget2.pointerdown();
247 - innerTarget1.blur({relatedTarget: innerNode2});
248 - innerTarget2.focus();
249 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(2);
250 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false);
251 - // then use keyboard again
252 - innerTarget2.keydown({key: 'Tab', shiftKey: true});
253 - innerTarget2.blur({relatedTarget: innerNode1});
254 - innerTarget1.focus();
255 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(3);
256 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true);
257 - // then use pointer on the target, focus should no longer be visible
258 - innerTarget1.pointerdown();
259 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(4);
260 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false);
261 - // onFocusVisibleChange should not be called again
262 - innerTarget1.blur({relatedTarget: container});
263 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(4);
264 - });
265 -
266 - // @gate www
267 - it('is not called after "focus" and "blur" events without keyboard', async () => {
268 - await componentInit();
269 - const innerTarget = createEventTarget(innerRef.current);
270 - innerTarget.pointerdown();
271 - innerTarget.pointerup();
272 - innerTarget.blur({relatedTarget: container});
273 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(0);
274 - });
275 -
276 - // @gate www
277 - it('is only called once when focus moves within and outside the subtree', async () => {
278 - await componentInit();
279 - const node = ref.current;
280 - const innerNode1 = innerRef.current;
281 - const innerNode2 = innerRef2.current;
282 - const target = createEventTarget(node);
283 - const innerTarget1 = createEventTarget(innerNode1);
284 - const innerTarget2 = createEventTarget(innerNode2);
285 -
286 - // focus shifts into subtree
287 - innerTarget1.focus();
288 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1);
289 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true);
290 - // focus moves around subtree
291 - innerTarget1.blur({relatedTarget: innerNode2});
292 - innerTarget2.focus();
293 - innerTarget2.blur({relatedTarget: node});
294 - target.focus();
295 - target.blur({relatedTarget: innerNode1});
296 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1);
297 - // focus shifts outside subtree
298 - innerTarget1.blur({relatedTarget: container});
299 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(2);
300 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false);
301 - });
302 - });
303 -
304 - // @gate www
305 - it('should correctly handle focus visibility when typing into an input', async () => {
306 - const onFocusWithinVisibleChange = jest.fn();
307 - const ref = React.createRef();
308 - const inputRef = React.createRef();
309 - const Component = () => {
310 - const focusWithinRef = useFocusWithin(ref, {
311 - onFocusWithinVisibleChange,
312 - });
313 - return (
314 - <div ref={focusWithinRef}>
315 - <input ref={inputRef} type="text" />
316 - </div>
317 - );
318 - };
319 - await act(() => {
320 - root.render(<Component />);
321 - });
322 -
323 - const target = createEventTarget(inputRef.current);
324 - // focus the target
325 - target.pointerdown();
326 - target.focus();
327 - target.keydown({key: 'a'});
328 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(0);
329 - });
330 -
331 - describe('onBeforeBlurWithin', () => {
332 - let onBeforeBlurWithin, onAfterBlurWithin, ref, innerRef, innerRef2;
333 -
334 - beforeEach(() => {
335 - onBeforeBlurWithin = jest.fn();
336 - onAfterBlurWithin = jest.fn(e => {
337 - e.persist();
338 - });
339 - ref = React.createRef();
340 - innerRef = React.createRef();
341 - innerRef2 = React.createRef();
342 - });
343 -
344 - // @gate www
345 - it('is called after a focused element is unmounted', async () => {
346 - const Component = ({show}) => {
347 - const focusWithinRef = useFocusWithin(ref, {
348 - onBeforeBlurWithin,
349 - onAfterBlurWithin,
350 - });
351 - return (
352 - <div ref={focusWithinRef}>
353 - {show && <input ref={innerRef} />}
354 - <div ref={innerRef2} />
355 - </div>
356 - );
357 - };
358 -
359 - await act(() => {
360 - root.render(<Component show={true} />);
361 - });
362 -
363 - const inner = innerRef.current;
364 - const target = createEventTarget(inner);
365 - target.keydown({key: 'Tab'});
366 - target.focus();
367 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0);
368 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(0);
369 - await act(() => {
370 - root.render(<Component show={false} />);
371 - });
372 -
373 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(1);
374 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(1);
375 - expect(onAfterBlurWithin).toHaveBeenCalledWith(
376 - expect.objectContaining({relatedTarget: inner}),
377 - );
378 - });
379 -
380 - // @gate www
381 - it('is called after a nested focused element is unmounted', async () => {
382 - const Component = ({show}) => {
383 - const focusWithinRef = useFocusWithin(ref, {
384 - onBeforeBlurWithin,
385 - onAfterBlurWithin,
386 - });
387 - return (
388 - <div ref={focusWithinRef}>
389 - {show && (
390 - <div>
391 - <input ref={innerRef} />
392 - </div>
393 - )}
394 - <div ref={innerRef2} />
395 - </div>
396 - );
397 - };
398 -
399 - await act(() => {
400 - root.render(<Component show={true} />);
401 - });
402 -
403 - const inner = innerRef.current;
404 - const target = createEventTarget(inner);
405 - target.keydown({key: 'Tab'});
406 - target.focus();
407 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0);
408 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(0);
409 -
410 - await act(() => {
411 - root.render(<Component show={false} />);
412 - });
413 -
414 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(1);
415 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(1);
416 - expect(onAfterBlurWithin).toHaveBeenCalledWith(
417 - expect.objectContaining({relatedTarget: inner}),
418 - );
419 - });
420 -
421 - // @gate www
422 - it('is called after many elements are unmounted', async () => {
423 - const buttonRef = React.createRef();
424 - const inputRef = React.createRef();
425 -
426 - const Component = ({show}) => {
427 - const focusWithinRef = useFocusWithin(ref, {
428 - onBeforeBlurWithin,
429 - onAfterBlurWithin,
430 - });
431 - return (
432 - <div ref={focusWithinRef}>
433 - {show && <button>Press me!</button>}
434 - {show && <button>Press me!</button>}
435 - {show && <input ref={inputRef} />}
436 - {show && <button>Press me!</button>}
437 - {!show && <button ref={buttonRef}>Press me!</button>}
438 - {show && <button>Press me!</button>}
439 - <button>Press me!</button>
440 - <button>Press me!</button>
441 - </div>
442 - );
443 - };
444 -
445 - await act(() => {
446 - root.render(<Component show={true} />);
447 - });
448 -
449 - inputRef.current.focus();
450 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0);
451 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(0);
452 - await act(() => {
453 - root.render(<Component show={false} />);
454 - });
455 -
456 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(1);
457 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(1);
458 - });
459 -
460 - // @gate www
461 - it('is called after a nested focused element is unmounted (with scope query)', async () => {
462 - const TestScope = React.unstable_Scope;
463 - const testScopeQuery = (type, props) => true;
464 - let targetNodes;
465 - let targetNode;
466 -
467 - const Component = ({show}) => {
468 - const scopeRef = React.useRef(null);
469 - const focusWithinRef = useFocusWithin(scopeRef, {
470 - onBeforeBlurWithin(event) {
471 - const scope = scopeRef.current;
472 - targetNode = innerRef.current;
473 - targetNodes = scope.DO_NOT_USE_queryAllNodes(testScopeQuery);
474 - },
475 - });
476 -
477 - return (
478 - <TestScope ref={focusWithinRef}>
479 - {show && <input ref={innerRef} />}
480 - </TestScope>
481 - );
482 - };
483 -
484 - await act(() => {
485 - root.render(<Component show={true} />);
486 - });
487 -
488 - const inner = innerRef.current;
489 - const target = createEventTarget(inner);
490 - target.keydown({key: 'Tab'});
491 - target.focus();
492 - await act(() => {
493 - root.render(<Component show={false} />);
494 - });
495 - expect(targetNodes).toEqual([targetNode]);
496 - });
497 -
498 - // @gate www
499 - it('is called after a focused suspended element is hidden', async () => {
500 - const Suspense = React.Suspense;
501 - let suspend = false;
502 - let resolve;
503 - const promise = new Promise(resolvePromise => (resolve = resolvePromise));
504 -
505 - function Child() {
506 - if (suspend) {
507 - throw promise;
508 - } else {
509 - return <input ref={innerRef} />;
510 - }
511 - }
512 -
513 - const Component = ({show}) => {
514 - const focusWithinRef = useFocusWithin(ref, {
515 - onBeforeBlurWithin,
516 - onAfterBlurWithin,
517 - });
518 -
519 - return (
520 - <div ref={focusWithinRef}>
521 - <Suspense fallback="Loading...">
522 - <Child />
523 - </Suspense>
524 - </div>
525 - );
526 - };
527 -
528 - const root2 = ReactDOMClient.createRoot(container2);
529 -
530 - await act(() => {
531 - root2.render(<Component />);
532 - });
533 - expect(container2.innerHTML).toBe('<div><input></div>');
534 -
535 - const inner = innerRef.current;
536 - const target = createEventTarget(inner);
537 - target.keydown({key: 'Tab'});
538 - target.focus();
539 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0);
540 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(0);
541 -
542 - suspend = true;
543 - await act(() => {
544 - root2.render(<Component />);
545 - });
546 - expect(container2.innerHTML).toBe(
547 - '<div><input style="display: none;">Loading...</div>',
548 - );
549 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(1);
550 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(1);
551 - await act(() => {
552 - suspend = false;
553 - resolve();
554 - });
555 - expect(container2.innerHTML).toBe('<div><input style=""></div>');
556 - });
557 -
558 - // @gate www
559 - it('is called after a focused suspended element is hidden then shown', async () => {
560 - const Suspense = React.Suspense;
561 - let suspend = false;
562 - let resolve;
563 - const promise = new Promise(resolvePromise => (resolve = resolvePromise));
564 - const buttonRef = React.createRef();
565 -
566 - function Child() {
567 - if (suspend) {
568 - throw promise;
569 - } else {
570 - return <input ref={innerRef} />;
571 - }
572 - }
573 -
574 - const Component = ({show}) => {
575 - const focusWithinRef = useFocusWithin(ref, {
576 - onBeforeBlurWithin,
577 - onAfterBlurWithin,
578 - });
579 -
580 - return (
581 - <div ref={focusWithinRef}>
582 - <Suspense fallback={<button ref={buttonRef}>Loading...</button>}>
583 - <Child />
584 - </Suspense>
585 - </div>
586 - );
587 - };
588 -
589 - const root2 = ReactDOMClient.createRoot(container2);
590 -
591 - await act(() => {
592 - root2.render(<Component />);
593 - });
594 -
595 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0);
596 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(0);
597 -
598 - suspend = true;
599 - await act(() => {
600 - root2.render(<Component />);
601 - });
602 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0);
603 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(0);
604 -
605 - await act(() => {
606 - root2.render(<Component />);
607 - });
608 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0);
609 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(0);
610 -
611 - buttonRef.current.focus();
612 - suspend = false;
613 - await act(() => {
614 - root2.render(<Component />);
615 - });
616 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(1);
617 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(1);
618 -
619 - await act(() => {
620 - suspend = false;
621 - resolve();
622 - });
623 - expect(container2.innerHTML).toBe('<div><input style=""></div>');
624 - });
625 - });
626 -});
packages/react-interactions/events/src/dom/create-event-handle/useEvent.js deleted
-72
@@ -1,72 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -import * as React from 'react';
11 -import * as ReactDOM from 'react-dom';
12 -
13 -const {useLayoutEffect, useRef} = React;
14 -const {unstable_createEventHandle} = ReactDOM;
15 -
16 -type UseEventHandle = {
17 - setListener: (
18 - target: EventTarget,
19 - null | ((SyntheticEvent<EventTarget>) => void),
20 - ) => void,
21 - clear: () => void,
22 -};
23 -
24 -export default function useEvent(
25 - event: string,
26 - options?: {
27 - capture?: boolean,
28 - },
29 -): UseEventHandle {
30 - const handleRef = useRef<UseEventHandle | null>(null);
31 - let useEventHandle = handleRef.current;
32 -
33 - if (useEventHandle === null) {
34 - const setEventHandle = unstable_createEventHandle(event, options);
35 - const clears = new Map<EventTarget, () => void>();
36 - useEventHandle = {
37 - setListener(
38 - target: EventTarget,
39 - callback: null | ((SyntheticEvent<EventTarget>) => void),
40 - ): void {
41 - let clear = clears.get(target);
42 - if (clear !== undefined) {
43 - clear();
44 - }
45 - if (callback === null) {
46 - clears.delete(target);
47 - return;
48 - }
49 - clear = setEventHandle(target, callback);
50 - clears.set(target, clear);
51 - },
52 - clear(): void {
53 - clears.forEach(c => {
54 - c();
55 - });
56 - clears.clear();
57 - },
58 - };
59 - handleRef.current = useEventHandle;
60 - }
61 -
62 - useLayoutEffect(() => {
63 - return () => {
64 - if (useEventHandle !== null) {
65 - useEventHandle.clear();
66 - }
67 - handleRef.current = null;
68 - };
69 - }, [useEventHandle]);
70 -
71 - return useEventHandle;
72 -}
packages/react-interactions/npm/drag.js deleted
-7
@@ -1,7 +0,0 @@
1 -'use strict';
2 -
3 -if (process.env.NODE_ENV === 'production') {
4 - module.exports = require('./cjs/react-interactions-events/drag.production.min.js');
5 -} else {
6 - module.exports = require('./cjs/react-interactions-events/drag.development.js');
7 -}
packages/react-interactions/npm/focus.js deleted
-7
@@ -1,7 +0,0 @@
1 -'use strict';
2 -
3 -if (process.env.NODE_ENV === 'production') {
4 - module.exports = require('./cjs/react-interactions-events/focus.production.min.js');
5 -} else {
6 - module.exports = require('./cjs/react-interactions-events/focus.development.js');
7 -}
packages/react-interactions/npm/hover.js deleted
-7
@@ -1,7 +0,0 @@
1 -'use strict';
2 -
3 -if (process.env.NODE_ENV === 'production') {
4 - module.exports = require('./cjs/react-interactions-events/hover.production.min.js');
5 -} else {
6 - module.exports = require('./cjs/react-interactions-events/hover.development.js');
7 -}
packages/react-interactions/npm/input.js deleted
-7
@@ -1,7 +0,0 @@
1 -'use strict';
2 -
3 -if (process.env.NODE_ENV === 'production') {
4 - module.exports = require('./cjs/react-interactions-events/input.production.min.js');
5 -} else {
6 - module.exports = require('./cjs/react-interactions-events/input.development.js');
7 -}
packages/react-interactions/npm/press-legacy.js deleted
-7
@@ -1,7 +0,0 @@
1 -'use strict';
2 -
3 -if (process.env.NODE_ENV === 'production') {
4 - module.exports = require('./cjs/react-interactions-events/press-legacy.production.min.js');
5 -} else {
6 - module.exports = require('./cjs/react-interactions-events/press-legacy.development.js');
7 -}
packages/react-interactions/npm/press.js deleted
-7
@@ -1,7 +0,0 @@
1 -'use strict';
2 -
3 -if (process.env.NODE_ENV === 'production') {
4 - module.exports = require('./cjs/react-interactions-events/press.production.min.js');
5 -} else {
6 - module.exports = require('./cjs/react-interactions-events/press.development.js');
7 -}
packages/react-interactions/npm/scroll.js deleted
-7
@@ -1,7 +0,0 @@
1 -'use strict';
2 -
3 -if (process.env.NODE_ENV === 'production') {
4 - module.exports = require('./cjs/react-interactions-events/scroll.production.min.js');
5 -} else {
6 - module.exports = require('./cjs/react-interactions-events/scroll.development.js');
7 -}
packages/react-interactions/npm/swipe.js deleted
-7
@@ -1,7 +0,0 @@
1 -'use strict';
2 -
3 -if (process.env.NODE_ENV === 'production') {
4 - module.exports = require('./cjs/react-interactions-events/swipe.production.min.js');
5 -} else {
6 - module.exports = require('./cjs/react-interactions-events/swipe.development.js');
7 -}
packages/react-interactions/npm/tap.js deleted
-7
@@ -1,7 +0,0 @@
1 -'use strict';
2 -
3 -if (process.env.NODE_ENV === 'production') {
4 - module.exports = require('./cjs/react-interactions-events/tap.production.min.js');
5 -} else {
6 - module.exports = require('./cjs/react-interactions-events/tap.development.js');
7 -}
packages/react-interactions/package.json deleted
-39
@@ -1,39 +0,0 @@
1 -{
2 - "name": "react-interactions",
3 - "private": true,
4 - "description": "React is a JavaScript library for building user interfaces.",
5 - "keywords": [
6 - "react"
7 - ],
8 - "version": "0.1.0",
9 - "homepage": "https://react.dev/",
10 - "bugs": "https://github.com/facebook/react/issues",
11 - "license": "MIT",
12 - "files": [
13 - "LICENSE",
14 - "README.md",
15 - "events/README.md",
16 - "events/context-menu.js",
17 - "events/focus.js",
18 - "events/hover.js",
19 - "events/input.js",
20 - "events/keyboard.js",
21 - "events/press.js",
22 - "events/press-legacy.js",
23 - "events/tap.js",
24 - "cjs/",
25 - "umd/"
26 - ],
27 - "main": "index.js",
28 - "repository": {
29 - "type": "git",
30 - "url": "https://github.com/facebook/react.git",
31 - "directory": "packages/react"
32 - },
33 - "engines": {
34 - "node": ">=0.10.0"
35 - },
36 - "peerDependencies": {
37 - "react": "^17.0.0"
38 - }
39 -}