Skip to content

Commit 85bd85a

Browse files
author
Gerardo
committed
Mobile -useKeyboardOffset: Update hook to use a setTiemout to remove the keyboard offset, it also updates the unit test
1 parent 8c31c52 commit 85bd85a

File tree

2 files changed

+132
-8
lines changed

2 files changed

+132
-8
lines changed

packages/components/src/mobile/keyboard-aware-flat-list/test/use-keyboard-offset.native.js

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import RCTDeviceEventEmitter from 'react-native/Libraries/EventEmitter/RCTDevice
1010
*/
1111
import useKeyboardOffset from '../use-keyboard-offset';
1212

13+
jest.useFakeTimers();
14+
1315
describe( 'useKeyboardOffset', () => {
1416
beforeEach( () => {
1517
Keyboard.removeAllListeners( 'keyboardDidShow' );
@@ -43,7 +45,10 @@ describe( 'useKeyboardOffset', () => {
4345

4446
it( 'updates keyboard visibility and offset when the keyboard is hidden', () => {
4547
// Arrange
46-
const { result } = renderHook( () => useKeyboardOffset( true ) );
48+
const shouldPreventAutomaticScroll = jest.fn().mockReturnValue( false );
49+
const { result } = renderHook( () =>
50+
useKeyboardOffset( true, shouldPreventAutomaticScroll )
51+
);
4752

4853
// Act
4954
act( () => {
@@ -54,6 +59,7 @@ describe( 'useKeyboardOffset', () => {
5459

5560
act( () => {
5661
RCTDeviceEventEmitter.emit( 'keyboardDidHide' );
62+
jest.runAllTimers();
5763
} );
5864

5965
// Assert
@@ -114,4 +120,105 @@ describe( 'useKeyboardOffset', () => {
114120
1
115121
);
116122
} );
123+
124+
it( 'sets keyboard offset to 0 when keyboard is hidden and shouldPreventAutomaticScroll is false', () => {
125+
// Arrange
126+
const shouldPreventAutomaticScroll = jest.fn().mockReturnValue( false );
127+
const { result } = renderHook( () =>
128+
useKeyboardOffset( true, shouldPreventAutomaticScroll )
129+
);
130+
131+
// Act
132+
act( () => {
133+
RCTDeviceEventEmitter.emit( 'keyboardDidShow', {
134+
endCoordinates: { height: 250 },
135+
} );
136+
} );
137+
act( () => {
138+
RCTDeviceEventEmitter.emit( 'keyboardDidHide' );
139+
jest.runAllTimers();
140+
} );
141+
142+
// Assert
143+
expect( result.current[ 0 ] ).toBe( 0 );
144+
} );
145+
146+
it( 'does not set keyboard offset to 0 when keyboard is hidden and shouldPreventAutomaticScroll is true', () => {
147+
// Arrange
148+
const shouldPreventAutomaticScroll = jest.fn().mockReturnValue( true );
149+
const { result } = renderHook( () =>
150+
useKeyboardOffset( true, shouldPreventAutomaticScroll )
151+
);
152+
153+
// Act
154+
act( () => {
155+
RCTDeviceEventEmitter.emit( 'keyboardDidShow', {
156+
endCoordinates: { height: 250 },
157+
} );
158+
} );
159+
act( () => {
160+
RCTDeviceEventEmitter.emit( 'keyboardDidHide' );
161+
jest.runAllTimers();
162+
} );
163+
164+
// Assert
165+
expect( result.current[ 0 ] ).toBe( 250 );
166+
} );
167+
168+
it( 'handles updates to shouldPreventAutomaticScroll', () => {
169+
// Arrange
170+
const preventScrollTrue = jest.fn( () => true );
171+
const preventScrollFalse = jest.fn( () => false );
172+
173+
// Act
174+
const { result, rerender } = renderHook(
175+
( { shouldPreventAutomaticScroll } ) =>
176+
useKeyboardOffset( true, shouldPreventAutomaticScroll ),
177+
{
178+
initialProps: {
179+
shouldPreventAutomaticScroll: preventScrollFalse,
180+
},
181+
}
182+
);
183+
184+
// Assert
185+
expect( result.current[ 0 ] ).toBe( 0 );
186+
187+
// Act
188+
act( () => {
189+
RCTDeviceEventEmitter.emit( 'keyboardDidShow', {
190+
endCoordinates: { height: 250 },
191+
} );
192+
} );
193+
194+
// Assert
195+
expect( result.current[ 0 ] ).toBe( 250 );
196+
197+
// Act
198+
act( () => {
199+
rerender( { shouldPreventAutomaticScroll: preventScrollTrue } );
200+
} );
201+
202+
act( () => {
203+
RCTDeviceEventEmitter.emit( 'keyboardDidHide' );
204+
jest.runAllTimers();
205+
} );
206+
207+
// Assert
208+
expect( result.current[ 0 ] ).toBe( 250 );
209+
210+
// Act
211+
act( () => {
212+
rerender( { shouldPreventAutomaticScroll: preventScrollFalse } );
213+
} );
214+
215+
act( () => {
216+
RCTDeviceEventEmitter.emit( 'keyboardDidShow', {
217+
endCoordinates: { height: 250 },
218+
} );
219+
} );
220+
221+
// Assert
222+
expect( result.current[ 0 ] ).toBe( 250 );
223+
} );
117224
} );

packages/components/src/mobile/keyboard-aware-flat-list/use-keyboard-offset.native.js

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,42 @@ import { Keyboard } from 'react-native';
77
/**
88
* WordPress dependencies
99
*/
10-
import { useEffect, useCallback, useState } from '@wordpress/element';
10+
import { useEffect, useCallback, useState, useRef } from '@wordpress/element';
1111

1212
/**
1313
* Hook that adds Keyboard listeners to get the offset space
1414
* when the keyboard is opened, taking into account focused AztecViews.
1515
*
16-
* @param {boolean} scrollEnabled Whether the scroll is enabled or not.
16+
* @param {boolean} scrollEnabled Whether the scroll is enabled or not.
17+
* @param {Function} shouldPreventAutomaticScroll Whether to prevent scrolling when there's a Keyboard offset set.
1718
* @return {[number]} Keyboard offset.
1819
*/
19-
export default function useKeyboardOffset( scrollEnabled ) {
20+
export default function useKeyboardOffset(
21+
scrollEnabled,
22+
shouldPreventAutomaticScroll
23+
) {
2024
const [ keyboardOffset, setKeyboardOffset ] = useState( 0 );
25+
const timeoutRef = useRef();
26+
27+
const onKeyboardDidHide = useCallback( () => {
28+
if ( shouldPreventAutomaticScroll() ) {
29+
clearTimeout( timeoutRef.current );
30+
return;
31+
}
32+
33+
// A timeout is being used to delay resetting the offset in cases
34+
// where the focus is changed to a different TextInput.
35+
clearTimeout( timeoutRef.current );
36+
timeoutRef.current = setTimeout( () => {
37+
setKeyboardOffset( 0 );
38+
}, 500 );
39+
}, [ shouldPreventAutomaticScroll ] );
2140

2241
const onKeyboardDidShow = useCallback( ( { endCoordinates } ) => {
42+
clearTimeout( timeoutRef.current );
2343
setKeyboardOffset( endCoordinates.height );
2444
}, [] );
2545

26-
const onKeyboardDidHide = useCallback( () => {
27-
setKeyboardOffset( 0 );
28-
}, [] );
29-
3046
useEffect( () => {
3147
let showSubscription;
3248
let hideSubscription;
@@ -46,6 +62,7 @@ export default function useKeyboardOffset( scrollEnabled ) {
4662
}
4763

4864
return () => {
65+
clearTimeout( timeoutRef.current );
4966
showSubscription?.remove();
5067
hideSubscription?.remove();
5168
};

0 commit comments

Comments
 (0)