Skip to content
Closed
44 changes: 44 additions & 0 deletions src/incubator/hooks/__tests__/useHiddenLocation.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {renderHook, act} from '@testing-library/react-hooks';
import {AccessibilityInfo} from 'react-native';
import {Constants} from '../../../commons/new';
import useHiddenLocation from '../useHiddenLocation';

describe('useHiddenLocation', () => {
const defaultExpectedLocation = {
up: -Constants.windowHeight,
down: Constants.windowHeight,
left: -Constants.screenWidth,
right: Constants.screenWidth,
wasMeasured: true
};

beforeEach(() => {
jest.spyOn(AccessibilityInfo, 'isReduceMotionEnabled').mockResolvedValue(false);
(AccessibilityInfo.addEventListener as jest.Mock) = jest.fn().mockImplementation((_event, _callback) => {
return {
remove: jest.fn()
};
});
});

afterEach(() => {
jest.clearAllMocks();
});

it('should return default positions when no layout is provided', () => {
const {result} = renderHook(() => useHiddenLocation());
expect(result.current.hiddenLocation).toEqual(defaultExpectedLocation);
});

it('should return defaultHiddenLocation on Android when reduce motion is enabled', async () => {
const originalIsAndroid = Constants.isAndroid;
Constants.isAndroid = true;
jest.spyOn(AccessibilityInfo, 'isReduceMotionEnabled').mockResolvedValue(true);
const {result} = renderHook(() => useHiddenLocation());
await act(async () => {
await Promise.resolve();
});
expect(result.current.hiddenLocation).toEqual(defaultExpectedLocation);
Constants.isAndroid = originalIsAndroid;
});
});
22 changes: 20 additions & 2 deletions src/incubator/hooks/useHiddenLocation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {isEqual} from 'lodash';
import {useCallback, useRef, useState, RefCallback} from 'react';
import {View, LayoutChangeEvent, LayoutRectangle} from 'react-native';
import {useCallback, useRef, useState, RefCallback, useEffect} from 'react';
import {View, LayoutChangeEvent, LayoutRectangle, AccessibilityInfo} from 'react-native';
import {Constants} from '../../commons/new';
import {PanningDirectionsEnum} from '../panView';

Expand All @@ -13,14 +13,32 @@ export interface HiddenLocation extends HiddenLocationRecord {
// Adding this for headless tests that are not triggering onLayout
const wasMeasuredDefaultValue = global._UILIB_TESTING ?? false;

const defaultHiddenLocation = {
up: -Constants.windowHeight,
down: Constants.windowHeight,
left: -Constants.screenWidth,
right: Constants.screenWidth,
wasMeasured: wasMeasuredDefaultValue
};

export default function useHiddenLocation<T extends View>() {
const [reduceMotionEnabled, setReduceMotionEnabled] = useState(false);

useEffect(() => {
AccessibilityInfo.isReduceMotionEnabled().then(setReduceMotionEnabled);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look in Constants -> accessibility is set with a promise, we can probably add the info there IMO.

}, []);

const getHiddenLocation = ({
x = 0,
y = 0,
width = Constants.screenWidth,
height = Constants.windowHeight,
wasMeasured = wasMeasuredDefaultValue
}): HiddenLocation => {
if (Constants.isAndroid && reduceMotionEnabled) {
return defaultHiddenLocation;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this just getHiddenLocation({})?
Maybe you can do it some other way?

}

return {
up: -y - height,
down: Constants.windowHeight - y,
Expand Down