@wordpress/components 23.7.0 → 23.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -6
- package/build/custom-gradient-picker/serializer.js +0 -4
- package/build/custom-gradient-picker/serializer.js.map +1 -1
- package/build/drop-zone/index.js +8 -8
- package/build/drop-zone/index.js.map +1 -1
- package/build/index.js.map +1 -1
- package/build/mobile/keyboard-aware-flat-list/index.android.js +0 -4
- package/build/mobile/keyboard-aware-flat-list/index.android.js.map +1 -1
- package/build/mobile/keyboard-aware-flat-list/index.ios.js +100 -55
- package/build/mobile/keyboard-aware-flat-list/index.ios.js.map +1 -1
- package/build/mobile/keyboard-aware-flat-list/use-keyboard-offset.native.js +82 -0
- package/build/mobile/keyboard-aware-flat-list/use-keyboard-offset.native.js.map +1 -0
- package/build/mobile/keyboard-aware-flat-list/use-scroll-to-text-input.native.js +85 -0
- package/build/mobile/keyboard-aware-flat-list/use-scroll-to-text-input.native.js.map +1 -0
- package/build/mobile/keyboard-aware-flat-list/use-text-input-caret-position.native.js +44 -0
- package/build/mobile/keyboard-aware-flat-list/use-text-input-caret-position.native.js.map +1 -0
- package/build/mobile/keyboard-aware-flat-list/use-text-input-offset.native.js +53 -0
- package/build/mobile/keyboard-aware-flat-list/use-text-input-offset.native.js.map +1 -0
- package/build/navigator/navigator-provider/component.js +4 -2
- package/build/navigator/navigator-provider/component.js.map +1 -1
- package/build/navigator/navigator-screen/component.js +4 -3
- package/build/navigator/navigator-screen/component.js.map +1 -1
- package/build/private-apis.js.map +1 -1
- package/build/query-controls/author-select.js +2 -1
- package/build/query-controls/author-select.js.map +1 -1
- package/build/query-controls/category-select.js +3 -1
- package/build/query-controls/category-select.js.map +1 -1
- package/build/query-controls/index.js +7 -1
- package/build/query-controls/index.js.map +1 -1
- package/build/sandbox/index.native.js +51 -28
- package/build/sandbox/index.native.js.map +1 -1
- package/build-module/custom-gradient-picker/serializer.js +0 -4
- package/build-module/custom-gradient-picker/serializer.js.map +1 -1
- package/build-module/drop-zone/index.js +8 -8
- package/build-module/drop-zone/index.js.map +1 -1
- package/build-module/index.js.map +1 -1
- package/build-module/mobile/keyboard-aware-flat-list/index.android.js +0 -4
- package/build-module/mobile/keyboard-aware-flat-list/index.android.js.map +1 -1
- package/build-module/mobile/keyboard-aware-flat-list/index.ios.js +97 -54
- package/build-module/mobile/keyboard-aware-flat-list/index.ios.js.map +1 -1
- package/build-module/mobile/keyboard-aware-flat-list/use-keyboard-offset.native.js +73 -0
- package/build-module/mobile/keyboard-aware-flat-list/use-keyboard-offset.native.js.map +1 -0
- package/build-module/mobile/keyboard-aware-flat-list/use-scroll-to-text-input.native.js +76 -0
- package/build-module/mobile/keyboard-aware-flat-list/use-scroll-to-text-input.native.js.map +1 -0
- package/build-module/mobile/keyboard-aware-flat-list/use-text-input-caret-position.native.js +33 -0
- package/build-module/mobile/keyboard-aware-flat-list/use-text-input-caret-position.native.js.map +1 -0
- package/build-module/mobile/keyboard-aware-flat-list/use-text-input-offset.native.js +40 -0
- package/build-module/mobile/keyboard-aware-flat-list/use-text-input-offset.native.js.map +1 -0
- package/build-module/navigator/navigator-provider/component.js +4 -2
- package/build-module/navigator/navigator-provider/component.js.map +1 -1
- package/build-module/navigator/navigator-screen/component.js +4 -3
- package/build-module/navigator/navigator-screen/component.js.map +1 -1
- package/build-module/private-apis.js.map +1 -1
- package/build-module/query-controls/author-select.js +2 -1
- package/build-module/query-controls/author-select.js.map +1 -1
- package/build-module/query-controls/category-select.js +3 -1
- package/build-module/query-controls/category-select.js.map +1 -1
- package/build-module/query-controls/index.js +7 -2
- package/build-module/query-controls/index.js.map +1 -1
- package/build-module/sandbox/index.native.js +52 -30
- package/build-module/sandbox/index.native.js.map +1 -1
- package/build-style/style-rtl.css +1 -1
- package/build-style/style.css +1 -1
- package/build-types/angle-picker-control/styles/angle-picker-control-styles.d.ts +1 -1
- package/build-types/border-box-control/border-box-control/hook.d.ts +2 -2
- package/build-types/border-box-control/border-box-control-linked-button/hook.d.ts +2 -2
- package/build-types/border-box-control/border-box-control-split-controls/hook.d.ts +2 -2
- package/build-types/border-box-control/border-box-control-visualizer/hook.d.ts +2 -2
- package/build-types/border-control/border-control/hook.d.ts +2 -2
- package/build-types/border-control/border-control-dropdown/hook.d.ts +2 -2
- package/build-types/border-control/border-control-style-picker/hook.d.ts +2 -2
- package/build-types/box-control/styles/box-control-styles.d.ts +5 -5
- package/build-types/button/deprecated.d.ts +2 -2
- package/build-types/card/card/hook.d.ts +2 -2
- package/build-types/card/card-body/hook.d.ts +2 -2
- package/build-types/card/card-divider/hook.d.ts +2 -2
- package/build-types/card/card-footer/hook.d.ts +2 -2
- package/build-types/card/card-header/hook.d.ts +2 -2
- package/build-types/card/card-media/hook.d.ts +2 -2
- package/build-types/color-palette/styles.d.ts +1 -1
- package/build-types/color-picker/styles.d.ts +5 -5
- package/build-types/combobox-control/styles.d.ts +1 -1
- package/build-types/custom-gradient-picker/serializer.d.ts +1 -5
- package/build-types/custom-gradient-picker/serializer.d.ts.map +1 -1
- package/build-types/custom-gradient-picker/types.d.ts +0 -2
- package/build-types/custom-gradient-picker/types.d.ts.map +1 -1
- package/build-types/date-time/date/styles.d.ts +2 -2
- package/build-types/date-time/date-time/styles.d.ts +1 -1
- package/build-types/date-time/time/styles.d.ts +8 -8
- package/build-types/drop-zone/index.d.ts.map +1 -1
- package/build-types/elevation/hook.d.ts +2 -2
- package/build-types/external-link/styles/external-link-styles.d.ts +1 -1
- package/build-types/flex/flex/hook.d.ts +2 -2
- package/build-types/flex/flex-block/hook.d.ts +2 -2
- package/build-types/flex/flex-item/hook.d.ts +2 -2
- package/build-types/focal-point-picker/styles/focal-point-picker-style.d.ts +2 -2
- package/build-types/form-token-field/styles.d.ts +1 -1
- package/build-types/grid/hook.d.ts +2 -2
- package/build-types/h-stack/hook.d.ts +2 -2
- package/build-types/heading/hook.d.ts +2 -2
- package/build-types/index.d.ts +128 -0
- package/build-types/index.d.ts.map +1 -0
- package/build-types/input-control/styles/input-control-styles.d.ts +2 -2
- package/build-types/item-group/item/hook.d.ts +2 -2
- package/build-types/item-group/item-group/hook.d.ts +2 -2
- package/build-types/navigation/styles/navigation-styles.d.ts +2 -2
- package/build-types/navigator/navigator-back-button/hook.d.ts +2 -2
- package/build-types/navigator/navigator-button/hook.d.ts +2 -2
- package/build-types/navigator/navigator-provider/component.d.ts.map +1 -1
- package/build-types/navigator/navigator-screen/component.d.ts +1 -1
- package/build-types/navigator/navigator-screen/component.d.ts.map +1 -1
- package/build-types/navigator/stories/index.d.ts +1 -0
- package/build-types/navigator/stories/index.d.ts.map +1 -1
- package/build-types/navigator/types.d.ts +2 -2
- package/build-types/navigator/types.d.ts.map +1 -1
- package/build-types/number-control/index.d.ts +2 -2
- package/build-types/number-control/stories/index.d.ts +2 -2
- package/build-types/palette-edit/styles.d.ts +3 -3
- package/build-types/popover/index.d.ts +1 -1
- package/build-types/popover/stories/e2e/index.d.ts +1 -1
- package/build-types/private-apis.d.ts +2 -3
- package/build-types/private-apis.d.ts.map +1 -1
- package/build-types/query-controls/author-select.d.ts.map +1 -1
- package/build-types/query-controls/category-select.d.ts.map +1 -1
- package/build-types/query-controls/index.d.ts.map +1 -1
- package/build-types/range-control/index.d.ts +1 -1
- package/build-types/range-control/styles/range-control-styles.d.ts +2 -2
- package/build-types/resizable-box/index.d.ts +1 -1
- package/build-types/resizable-box/resize-tooltip/index.d.ts +1 -1
- package/build-types/resizable-box/stories/index.d.ts +2 -2
- package/build-types/scrollable/hook.d.ts +2 -2
- package/build-types/search-control/index.d.ts +1 -1
- package/build-types/search-control/stories/index.d.ts +2 -2
- package/build-types/spacer/hook.d.ts +2 -2
- package/build-types/spinner/index.d.ts +1 -1
- package/build-types/surface/hook.d.ts +2 -2
- package/build-types/text/hook.d.ts +2 -2
- package/build-types/text-control/index.d.ts +1 -1
- package/build-types/toolbar/toolbar-button/index.d.ts +2 -2
- package/build-types/tools-panel/tools-panel/hook.d.ts +2 -2
- package/build-types/tools-panel/tools-panel-header/hook.d.ts +2 -2
- package/build-types/tools-panel/tools-panel-item/hook.d.ts +2 -2
- package/build-types/truncate/hook.d.ts +2 -2
- package/build-types/ui/control-group/hook.d.ts +2 -2
- package/build-types/ui/control-label/hook.d.ts +2 -2
- package/build-types/ui/form-group/form-group.d.ts +2 -2
- package/build-types/ui/form-group/use-form-group.d.ts +2 -2
- package/build-types/unit-control/index.d.ts +1 -1
- package/build-types/unit-control/styles/unit-control-styles.d.ts +2 -2
- package/build-types/v-stack/hook.d.ts +2 -2
- package/package.json +20 -19
- package/src/custom-gradient-picker/serializer.ts +2 -6
- package/src/custom-gradient-picker/types.ts +0 -18
- package/src/drop-zone/index.tsx +12 -8
- package/src/drop-zone/style.scss +1 -1
- package/src/mobile/keyboard-aware-flat-list/index.android.js +0 -4
- package/src/mobile/keyboard-aware-flat-list/index.ios.js +118 -67
- package/src/mobile/keyboard-aware-flat-list/test/use-keyboard-offset.native.js +203 -0
- package/src/mobile/keyboard-aware-flat-list/test/use-scroll-to-text-input.native.js +140 -0
- package/src/mobile/keyboard-aware-flat-list/test/use-text-input-caret-position.native.js +82 -0
- package/src/mobile/keyboard-aware-flat-list/test/use-text-input-offset.native.js +147 -0
- package/src/mobile/keyboard-aware-flat-list/use-keyboard-offset.native.js +87 -0
- package/src/mobile/keyboard-aware-flat-list/use-scroll-to-text-input.native.js +105 -0
- package/src/mobile/keyboard-aware-flat-list/use-text-input-caret-position.native.js +36 -0
- package/src/mobile/keyboard-aware-flat-list/use-text-input-offset.native.js +54 -0
- package/src/navigator/navigator-provider/component.tsx +2 -0
- package/src/navigator/navigator-screen/component.tsx +5 -2
- package/src/navigator/stories/index.tsx +68 -0
- package/src/navigator/test/index.tsx +52 -0
- package/src/navigator/types.ts +2 -1
- package/src/query-controls/author-select.tsx +1 -0
- package/src/query-controls/category-select.tsx +1 -0
- package/src/query-controls/index.tsx +4 -2
- package/src/sandbox/index.native.js +70 -36
- package/tsconfig.json +1 -2
- package/tsconfig.tsbuildinfo +1 -1
- /package/src/{index.js → index.ts} +0 -0
- /package/src/{private-apis.js → private-apis.ts} +0 -0
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
import { FlatList } from 'react-native';
|
|
6
|
-
import fastDeepEqual from 'fast-deep-equal/es6';
|
|
4
|
+
|
|
5
|
+
import { ScrollView, FlatList, useWindowDimensions } from 'react-native';
|
|
7
6
|
import Animated, {
|
|
8
7
|
useAnimatedScrollHandler,
|
|
9
8
|
useSharedValue,
|
|
@@ -12,36 +11,123 @@ import Animated, {
|
|
|
12
11
|
/**
|
|
13
12
|
* WordPress dependencies
|
|
14
13
|
*/
|
|
15
|
-
import {
|
|
14
|
+
import { useCallback, useEffect, useRef } from '@wordpress/element';
|
|
15
|
+
import { useThrottle } from '@wordpress/compose';
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Internal dependencies
|
|
19
|
+
*/
|
|
20
|
+
import useTextInputOffset from './use-text-input-offset';
|
|
21
|
+
import useKeyboardOffset from './use-keyboard-offset';
|
|
22
|
+
import useScrollToTextInput from './use-scroll-to-text-input';
|
|
23
|
+
import useTextInputCaretPosition from './use-text-input-caret-position';
|
|
21
24
|
|
|
25
|
+
const AnimatedScrollView = Animated.createAnimatedComponent( ScrollView );
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* React component that provides a FlatList that is aware of the keyboard state and can scroll
|
|
29
|
+
* to the currently focused TextInput.
|
|
30
|
+
*
|
|
31
|
+
* @param {Object} props Component props.
|
|
32
|
+
* @param {number} props.extraScrollHeight Extra scroll height for the content.
|
|
33
|
+
* @param {Function} props.innerRef Function to pass the ScrollView ref to the parent component.
|
|
34
|
+
* @param {Function} props.onScroll Function to be called when the list is scrolled.
|
|
35
|
+
* @param {boolean} props.scrollEnabled Whether the list can be scrolled.
|
|
36
|
+
* @param {Object} props.scrollViewStyle Additional style for the ScrollView component.
|
|
37
|
+
* @param {boolean} props.shouldPreventAutomaticScroll Whether to prevent scrolling when there's a Keyboard offset set.
|
|
38
|
+
* @param {Object} props... Other props to pass to the FlatList component.
|
|
39
|
+
* @return {WPComponent} KeyboardAwareFlatList component.
|
|
40
|
+
*/
|
|
22
41
|
export const KeyboardAwareFlatList = ( {
|
|
23
42
|
extraScrollHeight,
|
|
24
|
-
shouldPreventAutomaticScroll,
|
|
25
43
|
innerRef,
|
|
26
|
-
autoScroll,
|
|
27
|
-
scrollViewStyle,
|
|
28
|
-
inputAccessoryViewHeight,
|
|
29
44
|
onScroll,
|
|
30
|
-
|
|
45
|
+
scrollEnabled,
|
|
46
|
+
scrollViewStyle,
|
|
47
|
+
shouldPreventAutomaticScroll,
|
|
48
|
+
...props
|
|
31
49
|
} ) => {
|
|
32
50
|
const scrollViewRef = useRef();
|
|
33
|
-
const
|
|
51
|
+
const scrollViewMeasurements = useRef();
|
|
52
|
+
const scrollViewYOffset = useSharedValue( -1 );
|
|
53
|
+
|
|
54
|
+
const { height: windowHeight, width: windowWidth } = useWindowDimensions();
|
|
55
|
+
const isLandscape = windowWidth >= windowHeight;
|
|
56
|
+
|
|
57
|
+
const [ keyboardOffset ] = useKeyboardOffset(
|
|
58
|
+
scrollEnabled,
|
|
59
|
+
shouldPreventAutomaticScroll
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const [ currentCaretData ] = useTextInputCaretPosition( scrollEnabled );
|
|
63
|
+
|
|
64
|
+
const [ getTextInputOffset ] = useTextInputOffset(
|
|
65
|
+
scrollEnabled,
|
|
66
|
+
scrollViewRef
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const [ scrollToTextInputOffset ] = useScrollToTextInput(
|
|
70
|
+
extraScrollHeight,
|
|
71
|
+
keyboardOffset,
|
|
72
|
+
scrollEnabled,
|
|
73
|
+
scrollViewMeasurements,
|
|
74
|
+
scrollViewRef,
|
|
75
|
+
scrollViewYOffset
|
|
76
|
+
);
|
|
34
77
|
|
|
35
|
-
const
|
|
78
|
+
const onScrollToTextInput = useThrottle(
|
|
79
|
+
useCallback(
|
|
80
|
+
async ( caret ) => {
|
|
81
|
+
const textInputOffset = await getTextInputOffset( caret );
|
|
82
|
+
const hasTextInputOffset = textInputOffset !== null;
|
|
83
|
+
|
|
84
|
+
if ( hasTextInputOffset ) {
|
|
85
|
+
scrollToTextInputOffset( caret, textInputOffset );
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
[ getTextInputOffset, scrollToTextInputOffset ]
|
|
89
|
+
),
|
|
90
|
+
200,
|
|
91
|
+
{ leading: false }
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
useEffect( () => {
|
|
95
|
+
onScrollToTextInput( currentCaretData );
|
|
96
|
+
}, [ currentCaretData, onScrollToTextInput ] );
|
|
97
|
+
|
|
98
|
+
// When the orientation changes, the ScrollView measurements
|
|
99
|
+
// need to be re-calculated.
|
|
100
|
+
useEffect( () => {
|
|
101
|
+
scrollViewMeasurements.current = null;
|
|
102
|
+
}, [ isLandscape ] );
|
|
36
103
|
|
|
37
104
|
const scrollHandler = useAnimatedScrollHandler( {
|
|
38
105
|
onScroll: ( event ) => {
|
|
39
106
|
const { contentOffset } = event;
|
|
40
|
-
|
|
107
|
+
scrollViewYOffset.value = contentOffset.y;
|
|
41
108
|
onScroll( event );
|
|
42
109
|
},
|
|
43
110
|
} );
|
|
44
111
|
|
|
112
|
+
const measureScrollView = useCallback( () => {
|
|
113
|
+
if ( scrollViewRef.current ) {
|
|
114
|
+
const scrollRef = scrollViewRef.current.getNativeScrollRef();
|
|
115
|
+
|
|
116
|
+
scrollRef.measureInWindow( ( _x, y, width, height ) => {
|
|
117
|
+
scrollViewMeasurements.current = { y, width, height };
|
|
118
|
+
} );
|
|
119
|
+
}
|
|
120
|
+
}, [] );
|
|
121
|
+
|
|
122
|
+
const onContentSizeChange = useCallback( () => {
|
|
123
|
+
onScrollToTextInput( currentCaretData );
|
|
124
|
+
|
|
125
|
+
// Sets the first values when the content size changes.
|
|
126
|
+
if ( ! scrollViewMeasurements.current ) {
|
|
127
|
+
measureScrollView();
|
|
128
|
+
}
|
|
129
|
+
}, [ measureScrollView, onScrollToTextInput, currentCaretData ] );
|
|
130
|
+
|
|
45
131
|
const getRef = useCallback(
|
|
46
132
|
( ref ) => {
|
|
47
133
|
scrollViewRef.current = ref;
|
|
@@ -49,63 +135,28 @@ export const KeyboardAwareFlatList = ( {
|
|
|
49
135
|
},
|
|
50
136
|
[ innerRef ]
|
|
51
137
|
);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
! keyboardWillShowIndicator.current &&
|
|
59
|
-
latestContentOffsetY.value !== -1 &&
|
|
60
|
-
! shouldPreventAutomaticScroll()
|
|
61
|
-
) {
|
|
62
|
-
// Reset the content position if keyboard is still closed.
|
|
63
|
-
scrollViewRef.current?.scrollToPosition(
|
|
64
|
-
0,
|
|
65
|
-
latestContentOffsetY.value,
|
|
66
|
-
true
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
}, 50 );
|
|
70
|
-
}, [ latestContentOffsetY, shouldPreventAutomaticScroll ] );
|
|
71
|
-
const onKeyboardWillShow = useCallback( () => {
|
|
72
|
-
keyboardWillShowIndicator.current = true;
|
|
73
|
-
}, [] );
|
|
138
|
+
|
|
139
|
+
// Adds content insets when the keyboard is opened to have
|
|
140
|
+
// extra padding at the bottom.
|
|
141
|
+
const contentInset = { bottom: keyboardOffset };
|
|
142
|
+
|
|
143
|
+
const style = [ { flex: 1 }, scrollViewStyle ];
|
|
74
144
|
|
|
75
145
|
return (
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
enableResetScrollToCoords={ false }
|
|
146
|
+
<AnimatedScrollView
|
|
147
|
+
automaticallyAdjustContentInsets={ false }
|
|
148
|
+
contentInset={ contentInset }
|
|
80
149
|
keyboardShouldPersistTaps="handled"
|
|
81
|
-
|
|
82
|
-
extraHeight={ 0 }
|
|
83
|
-
inputAccessoryViewHeight={ inputAccessoryViewHeight }
|
|
84
|
-
enableAutomaticScroll={
|
|
85
|
-
autoScroll === undefined ? false : autoScroll
|
|
86
|
-
}
|
|
87
|
-
ref={ getRef }
|
|
88
|
-
onKeyboardWillHide={ onKeyboardWillHide }
|
|
89
|
-
onKeyboardDidHide={ onKeyboardDidHide }
|
|
90
|
-
onKeyboardWillShow={ onKeyboardWillShow }
|
|
91
|
-
scrollEnabled={ listProps.scrollEnabled }
|
|
150
|
+
onContentSizeChange={ onContentSizeChange }
|
|
92
151
|
onScroll={ scrollHandler }
|
|
152
|
+
ref={ getRef }
|
|
153
|
+
scrollEnabled={ scrollEnabled }
|
|
154
|
+
scrollEventThrottle={ 16 }
|
|
155
|
+
style={ style }
|
|
93
156
|
>
|
|
94
|
-
<
|
|
95
|
-
</
|
|
157
|
+
<FlatList { ...props } />
|
|
158
|
+
</AnimatedScrollView>
|
|
96
159
|
);
|
|
97
160
|
};
|
|
98
161
|
|
|
99
|
-
KeyboardAwareFlatList.handleCaretVerticalPositionChange = (
|
|
100
|
-
scrollView,
|
|
101
|
-
targetId,
|
|
102
|
-
caretY,
|
|
103
|
-
previousCaretY
|
|
104
|
-
) => {
|
|
105
|
-
if ( previousCaretY ) {
|
|
106
|
-
// If this is not the first tap.
|
|
107
|
-
scrollView.refreshScrollForField( targetId );
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
|
|
111
162
|
export default KeyboardAwareFlatList;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { act, renderHook } from '@testing-library/react-native';
|
|
5
|
+
import { Keyboard } from 'react-native';
|
|
6
|
+
import RCTDeviceEventEmitter from 'react-native/Libraries/EventEmitter/RCTDeviceEventEmitter';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Internal dependencies
|
|
10
|
+
*/
|
|
11
|
+
import useKeyboardOffset from '../use-keyboard-offset';
|
|
12
|
+
|
|
13
|
+
jest.useFakeTimers();
|
|
14
|
+
|
|
15
|
+
describe( 'useKeyboardOffset', () => {
|
|
16
|
+
beforeEach( () => {
|
|
17
|
+
Keyboard.removeAllListeners( 'keyboardDidShow' );
|
|
18
|
+
Keyboard.removeAllListeners( 'keyboardDidHide' );
|
|
19
|
+
Keyboard.removeAllListeners( 'keyboardWillShow' );
|
|
20
|
+
} );
|
|
21
|
+
|
|
22
|
+
it( 'returns the initial state', () => {
|
|
23
|
+
// Arrange
|
|
24
|
+
const { result } = renderHook( () => useKeyboardOffset( true ) );
|
|
25
|
+
const [ keyboardOffset ] = result.current;
|
|
26
|
+
|
|
27
|
+
// Assert
|
|
28
|
+
expect( keyboardOffset ).toBe( 0 );
|
|
29
|
+
} );
|
|
30
|
+
|
|
31
|
+
it( 'updates keyboard visibility and offset when the keyboard is shown', () => {
|
|
32
|
+
// Arrange
|
|
33
|
+
const { result } = renderHook( () => useKeyboardOffset( true ) );
|
|
34
|
+
|
|
35
|
+
// Act
|
|
36
|
+
act( () => {
|
|
37
|
+
RCTDeviceEventEmitter.emit( 'keyboardDidShow', {
|
|
38
|
+
endCoordinates: { height: 250 },
|
|
39
|
+
} );
|
|
40
|
+
} );
|
|
41
|
+
|
|
42
|
+
// Assert
|
|
43
|
+
const [ keyboardOffset ] = result.current;
|
|
44
|
+
expect( keyboardOffset ).toBe( 250 );
|
|
45
|
+
} );
|
|
46
|
+
|
|
47
|
+
it( 'updates keyboard visibility and offset when the keyboard is hidden', () => {
|
|
48
|
+
// Arrange
|
|
49
|
+
const shouldPreventAutomaticScroll = jest.fn().mockReturnValue( false );
|
|
50
|
+
const { result } = renderHook( () =>
|
|
51
|
+
useKeyboardOffset( true, shouldPreventAutomaticScroll )
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// Act
|
|
55
|
+
act( () => {
|
|
56
|
+
RCTDeviceEventEmitter.emit( 'keyboardDidShow', {
|
|
57
|
+
endCoordinates: { height: 250 },
|
|
58
|
+
} );
|
|
59
|
+
} );
|
|
60
|
+
|
|
61
|
+
act( () => {
|
|
62
|
+
RCTDeviceEventEmitter.emit( 'keyboardDidHide' );
|
|
63
|
+
jest.runAllTimers();
|
|
64
|
+
} );
|
|
65
|
+
|
|
66
|
+
// Assert
|
|
67
|
+
const [ keyboardOffset ] = result.current;
|
|
68
|
+
expect( keyboardOffset ).toBe( 0 );
|
|
69
|
+
} );
|
|
70
|
+
|
|
71
|
+
it( 'removes all keyboard listeners when scrollEnabled changes to false', () => {
|
|
72
|
+
// Arrange
|
|
73
|
+
const { result, rerender } = renderHook(
|
|
74
|
+
( { scrollEnabled } ) => useKeyboardOffset( scrollEnabled ),
|
|
75
|
+
{
|
|
76
|
+
initialProps: { scrollEnabled: true },
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
const [ keyboardOffset ] = result.current;
|
|
80
|
+
|
|
81
|
+
// Act
|
|
82
|
+
rerender( { scrollEnabled: false } );
|
|
83
|
+
|
|
84
|
+
// Assert
|
|
85
|
+
expect( keyboardOffset ).toBe( 0 );
|
|
86
|
+
expect( RCTDeviceEventEmitter.listenerCount( 'keyboardDidHide' ) ).toBe(
|
|
87
|
+
0
|
|
88
|
+
);
|
|
89
|
+
expect( RCTDeviceEventEmitter.listenerCount( 'keyboardDidShow' ) ).toBe(
|
|
90
|
+
0
|
|
91
|
+
);
|
|
92
|
+
} );
|
|
93
|
+
|
|
94
|
+
it( 'adds all keyboard listeners when scrollEnabled changes to true', () => {
|
|
95
|
+
// Arrange
|
|
96
|
+
const { result, rerender } = renderHook(
|
|
97
|
+
( { scrollEnabled } ) => useKeyboardOffset( scrollEnabled ),
|
|
98
|
+
{
|
|
99
|
+
initialProps: { scrollEnabled: false },
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
// Act
|
|
103
|
+
act( () => {
|
|
104
|
+
rerender( { scrollEnabled: true } );
|
|
105
|
+
} );
|
|
106
|
+
|
|
107
|
+
act( () => {
|
|
108
|
+
RCTDeviceEventEmitter.emit( 'keyboardDidShow', {
|
|
109
|
+
endCoordinates: { height: 250 },
|
|
110
|
+
} );
|
|
111
|
+
} );
|
|
112
|
+
|
|
113
|
+
const [ keyboardOffset ] = result.current;
|
|
114
|
+
|
|
115
|
+
// Assert
|
|
116
|
+
expect( keyboardOffset ).toBe( 250 );
|
|
117
|
+
expect( RCTDeviceEventEmitter.listenerCount( 'keyboardDidShow' ) ).toBe(
|
|
118
|
+
1
|
|
119
|
+
);
|
|
120
|
+
expect( RCTDeviceEventEmitter.listenerCount( 'keyboardDidHide' ) ).toBe(
|
|
121
|
+
1
|
|
122
|
+
);
|
|
123
|
+
} );
|
|
124
|
+
|
|
125
|
+
it( 'does not set keyboard offset to 0 when keyboard is hidden and shouldPreventAutomaticScroll is true', () => {
|
|
126
|
+
// Arrange
|
|
127
|
+
const shouldPreventAutomaticScroll = jest.fn().mockReturnValue( true );
|
|
128
|
+
const { result } = renderHook( () =>
|
|
129
|
+
useKeyboardOffset( true, shouldPreventAutomaticScroll )
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
// Act
|
|
133
|
+
act( () => {
|
|
134
|
+
RCTDeviceEventEmitter.emit( 'keyboardDidShow', {
|
|
135
|
+
endCoordinates: { height: 250 },
|
|
136
|
+
} );
|
|
137
|
+
} );
|
|
138
|
+
act( () => {
|
|
139
|
+
RCTDeviceEventEmitter.emit( 'keyboardDidHide' );
|
|
140
|
+
jest.runAllTimers();
|
|
141
|
+
} );
|
|
142
|
+
|
|
143
|
+
// Assert
|
|
144
|
+
expect( result.current[ 0 ] ).toBe( 250 );
|
|
145
|
+
} );
|
|
146
|
+
|
|
147
|
+
it( 'handles updates to shouldPreventAutomaticScroll', () => {
|
|
148
|
+
// Arrange
|
|
149
|
+
const preventScrollTrue = jest.fn( () => true );
|
|
150
|
+
const preventScrollFalse = jest.fn( () => false );
|
|
151
|
+
|
|
152
|
+
// Act
|
|
153
|
+
const { result, rerender } = renderHook(
|
|
154
|
+
( { shouldPreventAutomaticScroll } ) =>
|
|
155
|
+
useKeyboardOffset( true, shouldPreventAutomaticScroll ),
|
|
156
|
+
{
|
|
157
|
+
initialProps: {
|
|
158
|
+
shouldPreventAutomaticScroll: preventScrollFalse,
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Assert
|
|
164
|
+
expect( result.current[ 0 ] ).toBe( 0 );
|
|
165
|
+
|
|
166
|
+
// Act
|
|
167
|
+
act( () => {
|
|
168
|
+
RCTDeviceEventEmitter.emit( 'keyboardDidShow', {
|
|
169
|
+
endCoordinates: { height: 150 },
|
|
170
|
+
} );
|
|
171
|
+
} );
|
|
172
|
+
|
|
173
|
+
// Assert
|
|
174
|
+
expect( result.current[ 0 ] ).toBe( 150 );
|
|
175
|
+
|
|
176
|
+
// Act
|
|
177
|
+
act( () => {
|
|
178
|
+
rerender( { shouldPreventAutomaticScroll: preventScrollTrue } );
|
|
179
|
+
} );
|
|
180
|
+
|
|
181
|
+
act( () => {
|
|
182
|
+
RCTDeviceEventEmitter.emit( 'keyboardDidHide' );
|
|
183
|
+
jest.runAllTimers();
|
|
184
|
+
} );
|
|
185
|
+
|
|
186
|
+
// Assert
|
|
187
|
+
expect( result.current[ 0 ] ).toBe( 150 );
|
|
188
|
+
|
|
189
|
+
// Act
|
|
190
|
+
act( () => {
|
|
191
|
+
rerender( { shouldPreventAutomaticScroll: preventScrollFalse } );
|
|
192
|
+
} );
|
|
193
|
+
|
|
194
|
+
act( () => {
|
|
195
|
+
RCTDeviceEventEmitter.emit( 'keyboardDidShow', {
|
|
196
|
+
endCoordinates: { height: 250 },
|
|
197
|
+
} );
|
|
198
|
+
} );
|
|
199
|
+
|
|
200
|
+
// Assert
|
|
201
|
+
expect( result.current[ 0 ] ).toBe( 250 );
|
|
202
|
+
} );
|
|
203
|
+
} );
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { renderHook } from '@testing-library/react-native';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Internal dependencies
|
|
9
|
+
*/
|
|
10
|
+
import useScrollToTextInput from '../use-scroll-to-text-input';
|
|
11
|
+
|
|
12
|
+
describe( 'useScrollToTextInput', () => {
|
|
13
|
+
it( 'scrolls up to the current TextInput offset', () => {
|
|
14
|
+
// Arrange
|
|
15
|
+
const currentCaretData = { caretHeight: 10 };
|
|
16
|
+
const extraScrollHeight = 50;
|
|
17
|
+
const keyboardOffset = 100;
|
|
18
|
+
const scrollEnabled = true;
|
|
19
|
+
const scrollViewRef = { current: { scrollTo: jest.fn() } };
|
|
20
|
+
const scrollViewMeasurements = { current: { height: 600 } };
|
|
21
|
+
const scrollViewYOffset = { value: 150 };
|
|
22
|
+
const textInputOffset = 50;
|
|
23
|
+
|
|
24
|
+
const { result } = renderHook( () =>
|
|
25
|
+
useScrollToTextInput(
|
|
26
|
+
extraScrollHeight,
|
|
27
|
+
keyboardOffset,
|
|
28
|
+
scrollEnabled,
|
|
29
|
+
scrollViewMeasurements,
|
|
30
|
+
scrollViewRef,
|
|
31
|
+
scrollViewYOffset
|
|
32
|
+
)
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
// Act
|
|
36
|
+
result.current[ 0 ]( currentCaretData, textInputOffset );
|
|
37
|
+
|
|
38
|
+
// Assert
|
|
39
|
+
expect( scrollViewRef.current.scrollTo ).toHaveBeenCalledWith( {
|
|
40
|
+
y: textInputOffset,
|
|
41
|
+
animated: true,
|
|
42
|
+
} );
|
|
43
|
+
} );
|
|
44
|
+
|
|
45
|
+
it( 'scrolls down to the current TextInput offset', () => {
|
|
46
|
+
// Arrange
|
|
47
|
+
const currentCaretData = { caretHeight: 10 };
|
|
48
|
+
const extraScrollHeight = 50;
|
|
49
|
+
const keyboardOffset = 100;
|
|
50
|
+
const scrollEnabled = true;
|
|
51
|
+
const scrollViewRef = { current: { scrollTo: jest.fn() } };
|
|
52
|
+
const scrollViewMeasurements = { current: { height: 600 } };
|
|
53
|
+
const scrollViewYOffset = { value: 250 };
|
|
54
|
+
const textInputOffset = 750;
|
|
55
|
+
|
|
56
|
+
const { result } = renderHook( () =>
|
|
57
|
+
useScrollToTextInput(
|
|
58
|
+
extraScrollHeight,
|
|
59
|
+
keyboardOffset,
|
|
60
|
+
scrollEnabled,
|
|
61
|
+
scrollViewMeasurements,
|
|
62
|
+
scrollViewRef,
|
|
63
|
+
scrollViewYOffset
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// Act
|
|
68
|
+
result.current[ 0 ]( currentCaretData, textInputOffset );
|
|
69
|
+
|
|
70
|
+
// Assert
|
|
71
|
+
const expectedYOffset =
|
|
72
|
+
textInputOffset -
|
|
73
|
+
( scrollViewMeasurements.current.height -
|
|
74
|
+
( keyboardOffset +
|
|
75
|
+
extraScrollHeight +
|
|
76
|
+
currentCaretData.caretHeight ) );
|
|
77
|
+
expect( scrollViewRef.current.scrollTo ).toHaveBeenCalledWith( {
|
|
78
|
+
y: expectedYOffset,
|
|
79
|
+
animated: true,
|
|
80
|
+
} );
|
|
81
|
+
} );
|
|
82
|
+
|
|
83
|
+
it( 'does not scroll when the ScrollView ref is not available', () => {
|
|
84
|
+
// Arrange
|
|
85
|
+
const currentCaretData = { caretHeight: 10 };
|
|
86
|
+
const extraScrollHeight = 50;
|
|
87
|
+
const keyboardOffset = 100;
|
|
88
|
+
const scrollEnabled = true;
|
|
89
|
+
const scrollViewRef = { current: null };
|
|
90
|
+
const scrollViewMeasurements = { current: { height: 600 } };
|
|
91
|
+
const scrollViewYOffset = { value: 0 };
|
|
92
|
+
const textInputOffset = 50;
|
|
93
|
+
|
|
94
|
+
const { result } = renderHook( () =>
|
|
95
|
+
useScrollToTextInput(
|
|
96
|
+
extraScrollHeight,
|
|
97
|
+
keyboardOffset,
|
|
98
|
+
scrollEnabled,
|
|
99
|
+
scrollViewMeasurements,
|
|
100
|
+
scrollViewRef,
|
|
101
|
+
scrollViewYOffset
|
|
102
|
+
)
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
// Act
|
|
106
|
+
result.current[ 0 ]( currentCaretData, textInputOffset );
|
|
107
|
+
|
|
108
|
+
// Assert
|
|
109
|
+
expect( scrollViewRef.current ).toBeNull();
|
|
110
|
+
} );
|
|
111
|
+
|
|
112
|
+
it( 'does not scroll when the scroll is not enabled', () => {
|
|
113
|
+
// Arrange
|
|
114
|
+
const currentCaretData = { caretHeight: 10 };
|
|
115
|
+
const extraScrollHeight = 50;
|
|
116
|
+
const keyboardOffset = 100;
|
|
117
|
+
const scrollEnabled = false;
|
|
118
|
+
const scrollViewRef = { current: { scrollTo: jest.fn() } };
|
|
119
|
+
const scrollViewMeasurements = { current: { height: 600 } };
|
|
120
|
+
const scrollViewYOffset = { value: 0 };
|
|
121
|
+
const textInputOffset = 50;
|
|
122
|
+
|
|
123
|
+
const { result } = renderHook( () =>
|
|
124
|
+
useScrollToTextInput(
|
|
125
|
+
extraScrollHeight,
|
|
126
|
+
keyboardOffset,
|
|
127
|
+
scrollEnabled,
|
|
128
|
+
scrollViewMeasurements,
|
|
129
|
+
scrollViewRef,
|
|
130
|
+
scrollViewYOffset
|
|
131
|
+
)
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
// Act
|
|
135
|
+
result.current[ 0 ]( currentCaretData, textInputOffset );
|
|
136
|
+
|
|
137
|
+
// Assert
|
|
138
|
+
expect( scrollViewRef.current.scrollTo ).not.toHaveBeenCalled();
|
|
139
|
+
} );
|
|
140
|
+
} );
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { renderHook } from '@testing-library/react-native';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* WordPress dependencies
|
|
8
|
+
*/
|
|
9
|
+
import RCTAztecView from '@wordpress/react-native-aztec';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Internal dependencies
|
|
13
|
+
*/
|
|
14
|
+
import useTextInputCaretPosition from '../use-text-input-caret-position';
|
|
15
|
+
|
|
16
|
+
describe( 'useTextInputCaretPosition', () => {
|
|
17
|
+
let addCaretChangeListenerSpy;
|
|
18
|
+
let removeCaretChangeListenerSpy;
|
|
19
|
+
|
|
20
|
+
beforeAll( () => {
|
|
21
|
+
addCaretChangeListenerSpy = jest.spyOn(
|
|
22
|
+
RCTAztecView.InputState,
|
|
23
|
+
'addCaretChangeListener'
|
|
24
|
+
);
|
|
25
|
+
removeCaretChangeListenerSpy = jest.spyOn(
|
|
26
|
+
RCTAztecView.InputState,
|
|
27
|
+
'removeCaretChangeListener'
|
|
28
|
+
);
|
|
29
|
+
} );
|
|
30
|
+
|
|
31
|
+
beforeEach( () => {
|
|
32
|
+
addCaretChangeListenerSpy.mockClear();
|
|
33
|
+
removeCaretChangeListenerSpy.mockClear();
|
|
34
|
+
} );
|
|
35
|
+
|
|
36
|
+
it( 'should add and remove caret change listener correctly', () => {
|
|
37
|
+
// Arrange
|
|
38
|
+
const scrollEnabled = true;
|
|
39
|
+
|
|
40
|
+
// Act
|
|
41
|
+
const { unmount } = renderHook( () =>
|
|
42
|
+
useTextInputCaretPosition( scrollEnabled )
|
|
43
|
+
);
|
|
44
|
+
unmount();
|
|
45
|
+
|
|
46
|
+
// Assert
|
|
47
|
+
expect( addCaretChangeListenerSpy ).toHaveBeenCalledTimes( 1 );
|
|
48
|
+
expect( removeCaretChangeListenerSpy ).toHaveBeenCalledTimes( 1 );
|
|
49
|
+
} );
|
|
50
|
+
|
|
51
|
+
it( 'should add caret change listener when scroll is enabled', () => {
|
|
52
|
+
// Arrange
|
|
53
|
+
const scrollEnabled = true;
|
|
54
|
+
|
|
55
|
+
// Act
|
|
56
|
+
renderHook( () => useTextInputCaretPosition( scrollEnabled ) );
|
|
57
|
+
|
|
58
|
+
// Assert
|
|
59
|
+
expect( addCaretChangeListenerSpy ).toHaveBeenCalledTimes( 1 );
|
|
60
|
+
expect( removeCaretChangeListenerSpy ).not.toHaveBeenCalled();
|
|
61
|
+
} );
|
|
62
|
+
|
|
63
|
+
it( 'should remove caret change listener when scroll is enabled and then changed to disabled', () => {
|
|
64
|
+
// Arrange
|
|
65
|
+
const { rerender } = renderHook(
|
|
66
|
+
( props ) => useTextInputCaretPosition( props.scrollEnabled ),
|
|
67
|
+
{
|
|
68
|
+
initialProps: { scrollEnabled: true },
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// Assert
|
|
73
|
+
expect( addCaretChangeListenerSpy ).toHaveBeenCalled();
|
|
74
|
+
|
|
75
|
+
// Act
|
|
76
|
+
rerender( { scrollEnabled: false } );
|
|
77
|
+
|
|
78
|
+
// Assert
|
|
79
|
+
expect( removeCaretChangeListenerSpy ).toHaveBeenCalled();
|
|
80
|
+
expect( addCaretChangeListenerSpy ).toHaveBeenCalledTimes( 1 );
|
|
81
|
+
} );
|
|
82
|
+
} );
|