@hero-design/rn 8.64.0 → 8.64.1
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +6 -0
- package/es/index.js +34 -19
- package/lib/index.js +34 -19
- package/package.json +1 -1
- package/src/components/Tabs/ScrollableTabs.tsx +10 -16
- package/src/components/Tabs/__tests__/ScrollableTabs.spec.tsx +32 -0
- package/src/components/Tabs/__tests__/index.spec.tsx +32 -0
- package/src/components/Tabs/index.tsx +12 -8
- package/src/components/Tabs/useHandlePageScroll.tsx +32 -0
- package/stats/8.64.0/rn-stats.html +2 -0
- package/stats/8.64.1/rn-stats.html +4842 -0
- package/types/components/Tabs/index.d.ts +1 -1
- package/types/components/Tabs/useHandlePageScroll.d.ts +8 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
[1msrc/index.ts[22m → [1mlib/index.js, es/index.js[22m...[39m
|
|
3
3
|
[1m[33m(!) Plugin replace: @rollup/plugin-replace: 'preventAssignment' currently defaults to false. It is recommended to set this option to `true`, as the next major version will default this option to `true`.[39m[22m
|
|
4
4
|
[1m[33m(!) Plugin node-resolve: preferring built-in module 'events' over local alternative at '/home/runner/work/hero-design/hero-design/node_modules/events/events.js', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning[39m[22m
|
|
5
|
-
[32mcreated [1mlib/index.js, es/index.js[22m in [1m1m
|
|
5
|
+
[32mcreated [1mlib/index.js, es/index.js[22m in [1m1m 4.4s[22m[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @hero-design/rn
|
|
2
2
|
|
|
3
|
+
## 8.64.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#3246](https://github.com/Thinkei/hero-design/pull/3246) [`1dbb5e198`](https://github.com/Thinkei/hero-design/commit/1dbb5e1985e4b316ca08cd39c10d4d0779aaa43d) Thanks [@vinhphan-eh](https://github.com/vinhphan-eh)! - [Tabs] Fix onTabPress being called on render
|
|
8
|
+
|
|
3
9
|
## 8.64.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/es/index.js
CHANGED
|
@@ -17871,6 +17871,20 @@ var ScrollableTabHeader = function ScrollableTabHeader(_ref2) {
|
|
|
17871
17871
|
}));
|
|
17872
17872
|
};
|
|
17873
17873
|
|
|
17874
|
+
var useHandlePageScroll = function useHandlePageScroll() {
|
|
17875
|
+
// Used as a flag to prevent calling onTabPress on initial render
|
|
17876
|
+
var hasScrolled = useRef(false);
|
|
17877
|
+
var onPageScrollStateChanged = useCallback(function (e) {
|
|
17878
|
+
if (!hasScrolled.current && e.nativeEvent.pageScrollState === 'dragging') {
|
|
17879
|
+
hasScrolled.current = true;
|
|
17880
|
+
}
|
|
17881
|
+
}, []);
|
|
17882
|
+
return {
|
|
17883
|
+
onPageScrollStateChanged: onPageScrollStateChanged,
|
|
17884
|
+
hasScrolled: hasScrolled
|
|
17885
|
+
};
|
|
17886
|
+
};
|
|
17887
|
+
|
|
17874
17888
|
var TabContext = /*#__PURE__*/React__default.createContext(null);
|
|
17875
17889
|
var ScreenContext = /*#__PURE__*/React__default.createContext(null);
|
|
17876
17890
|
var useIsFocused = function useIsFocused() {
|
|
@@ -17898,14 +17912,15 @@ var ScrollableTab = function ScrollableTab(_ref) {
|
|
|
17898
17912
|
componentTestID = _ref.testID,
|
|
17899
17913
|
_ref$variant = _ref.variant,
|
|
17900
17914
|
variant = _ref$variant === void 0 ? 'highlighted' : _ref$variant;
|
|
17901
|
-
var pagerViewRef =
|
|
17915
|
+
var pagerViewRef = useRef(null);
|
|
17902
17916
|
var insets = useSafeAreaInsets();
|
|
17903
17917
|
var selectedTabIndex = tabs.findIndex(function (item) {
|
|
17904
17918
|
return item.key === selectedTabKey;
|
|
17905
17919
|
});
|
|
17906
|
-
|
|
17907
|
-
|
|
17908
|
-
|
|
17920
|
+
var _useHandlePageScroll = useHandlePageScroll(),
|
|
17921
|
+
hasScrolled = _useHandlePageScroll.hasScrolled,
|
|
17922
|
+
onPageScrollStateChanged = _useHandlePageScroll.onPageScrollStateChanged;
|
|
17923
|
+
useEffect(function () {
|
|
17909
17924
|
var timeoutHandle;
|
|
17910
17925
|
if (selectedTabIndex !== -1) {
|
|
17911
17926
|
// If the selected tab is changed too quickly, the setPage is crashed and not work anymore
|
|
@@ -17922,7 +17937,7 @@ var ScrollableTab = function ScrollableTab(_ref) {
|
|
|
17922
17937
|
}
|
|
17923
17938
|
};
|
|
17924
17939
|
}, [selectedTabIndex, pagerViewRef]);
|
|
17925
|
-
var tabContextProviderValue =
|
|
17940
|
+
var tabContextProviderValue = useMemo(function () {
|
|
17926
17941
|
return {
|
|
17927
17942
|
selectedTabKey: selectedTabKey
|
|
17928
17943
|
};
|
|
@@ -17944,11 +17959,7 @@ var ScrollableTab = function ScrollableTab(_ref) {
|
|
|
17944
17959
|
useNext: true,
|
|
17945
17960
|
initialPage: selectedTabIndex,
|
|
17946
17961
|
ref: pagerViewRef,
|
|
17947
|
-
onPageScrollStateChanged:
|
|
17948
|
-
if (!hasScrolled.current && e.nativeEvent.pageScrollState === 'dragging') {
|
|
17949
|
-
hasScrolled.current = true;
|
|
17950
|
-
}
|
|
17951
|
-
},
|
|
17962
|
+
onPageScrollStateChanged: onPageScrollStateChanged,
|
|
17952
17963
|
onPageSelected: function onPageSelected(e) {
|
|
17953
17964
|
var index = e.nativeEvent.position;
|
|
17954
17965
|
var selectedItem = tabs[index];
|
|
@@ -18012,23 +18023,26 @@ var Tabs = function Tabs(_ref2) {
|
|
|
18012
18023
|
componentTestID = _ref2.testID;
|
|
18013
18024
|
var theme = useTheme$1();
|
|
18014
18025
|
var insets = useSafeAreaInsets();
|
|
18015
|
-
var pagerViewRef =
|
|
18026
|
+
var pagerViewRef = useRef(null);
|
|
18016
18027
|
var selectedTabIndex = tabs.findIndex(function (item) {
|
|
18017
18028
|
return item.key === selectedTabKey;
|
|
18018
18029
|
});
|
|
18019
|
-
var scrollOffsetAnimatedValue =
|
|
18020
|
-
var positionAnimatedValue =
|
|
18021
|
-
var
|
|
18022
|
-
|
|
18023
|
-
tabsWidth =
|
|
18024
|
-
setTabsWidth =
|
|
18030
|
+
var scrollOffsetAnimatedValue = useRef(new Animated.Value(0)).current;
|
|
18031
|
+
var positionAnimatedValue = useRef(new Animated.Value(0)).current;
|
|
18032
|
+
var _useState = useState(0),
|
|
18033
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
18034
|
+
tabsWidth = _useState2[0],
|
|
18035
|
+
setTabsWidth = _useState2[1];
|
|
18036
|
+
var _useHandlePageScroll = useHandlePageScroll(),
|
|
18037
|
+
onPageScrollStateChanged = _useHandlePageScroll.onPageScrollStateChanged,
|
|
18038
|
+
hasScrolled = _useHandlePageScroll.hasScrolled;
|
|
18025
18039
|
useEffect(function () {
|
|
18026
18040
|
if (selectedTabIndex !== -1) {
|
|
18027
18041
|
var _pagerViewRef$current;
|
|
18028
18042
|
(_pagerViewRef$current = pagerViewRef.current) === null || _pagerViewRef$current === void 0 || _pagerViewRef$current.setPage(selectedTabIndex);
|
|
18029
18043
|
}
|
|
18030
18044
|
}, [selectedTabIndex]);
|
|
18031
|
-
var tabContextProviderValue =
|
|
18045
|
+
var tabContextProviderValue = useMemo(function () {
|
|
18032
18046
|
return {
|
|
18033
18047
|
selectedTabKey: selectedTabKey
|
|
18034
18048
|
};
|
|
@@ -18084,10 +18098,11 @@ var Tabs = function Tabs(_ref2) {
|
|
|
18084
18098
|
onPageSelected: function onPageSelected(e) {
|
|
18085
18099
|
var index = e.nativeEvent.position;
|
|
18086
18100
|
var selectedItem = tabs[index];
|
|
18087
|
-
if (selectedItem) {
|
|
18101
|
+
if (hasScrolled.current && selectedItem) {
|
|
18088
18102
|
onTabPress(selectedItem.key);
|
|
18089
18103
|
}
|
|
18090
18104
|
},
|
|
18105
|
+
onPageScrollStateChanged: onPageScrollStateChanged,
|
|
18091
18106
|
onPageScroll: Animated.event([{
|
|
18092
18107
|
nativeEvent: {
|
|
18093
18108
|
offset: scrollOffsetAnimatedValue,
|
package/lib/index.js
CHANGED
|
@@ -17901,6 +17901,20 @@ var ScrollableTabHeader = function ScrollableTabHeader(_ref2) {
|
|
|
17901
17901
|
}));
|
|
17902
17902
|
};
|
|
17903
17903
|
|
|
17904
|
+
var useHandlePageScroll = function useHandlePageScroll() {
|
|
17905
|
+
// Used as a flag to prevent calling onTabPress on initial render
|
|
17906
|
+
var hasScrolled = React.useRef(false);
|
|
17907
|
+
var onPageScrollStateChanged = React.useCallback(function (e) {
|
|
17908
|
+
if (!hasScrolled.current && e.nativeEvent.pageScrollState === 'dragging') {
|
|
17909
|
+
hasScrolled.current = true;
|
|
17910
|
+
}
|
|
17911
|
+
}, []);
|
|
17912
|
+
return {
|
|
17913
|
+
onPageScrollStateChanged: onPageScrollStateChanged,
|
|
17914
|
+
hasScrolled: hasScrolled
|
|
17915
|
+
};
|
|
17916
|
+
};
|
|
17917
|
+
|
|
17904
17918
|
var TabContext = /*#__PURE__*/React__default["default"].createContext(null);
|
|
17905
17919
|
var ScreenContext = /*#__PURE__*/React__default["default"].createContext(null);
|
|
17906
17920
|
var useIsFocused = function useIsFocused() {
|
|
@@ -17928,14 +17942,15 @@ var ScrollableTab = function ScrollableTab(_ref) {
|
|
|
17928
17942
|
componentTestID = _ref.testID,
|
|
17929
17943
|
_ref$variant = _ref.variant,
|
|
17930
17944
|
variant = _ref$variant === void 0 ? 'highlighted' : _ref$variant;
|
|
17931
|
-
var pagerViewRef =
|
|
17945
|
+
var pagerViewRef = React.useRef(null);
|
|
17932
17946
|
var insets = reactNativeSafeAreaContext.useSafeAreaInsets();
|
|
17933
17947
|
var selectedTabIndex = tabs.findIndex(function (item) {
|
|
17934
17948
|
return item.key === selectedTabKey;
|
|
17935
17949
|
});
|
|
17936
|
-
|
|
17937
|
-
|
|
17938
|
-
|
|
17950
|
+
var _useHandlePageScroll = useHandlePageScroll(),
|
|
17951
|
+
hasScrolled = _useHandlePageScroll.hasScrolled,
|
|
17952
|
+
onPageScrollStateChanged = _useHandlePageScroll.onPageScrollStateChanged;
|
|
17953
|
+
React.useEffect(function () {
|
|
17939
17954
|
var timeoutHandle;
|
|
17940
17955
|
if (selectedTabIndex !== -1) {
|
|
17941
17956
|
// If the selected tab is changed too quickly, the setPage is crashed and not work anymore
|
|
@@ -17952,7 +17967,7 @@ var ScrollableTab = function ScrollableTab(_ref) {
|
|
|
17952
17967
|
}
|
|
17953
17968
|
};
|
|
17954
17969
|
}, [selectedTabIndex, pagerViewRef]);
|
|
17955
|
-
var tabContextProviderValue =
|
|
17970
|
+
var tabContextProviderValue = React.useMemo(function () {
|
|
17956
17971
|
return {
|
|
17957
17972
|
selectedTabKey: selectedTabKey
|
|
17958
17973
|
};
|
|
@@ -17974,11 +17989,7 @@ var ScrollableTab = function ScrollableTab(_ref) {
|
|
|
17974
17989
|
useNext: true,
|
|
17975
17990
|
initialPage: selectedTabIndex,
|
|
17976
17991
|
ref: pagerViewRef,
|
|
17977
|
-
onPageScrollStateChanged:
|
|
17978
|
-
if (!hasScrolled.current && e.nativeEvent.pageScrollState === 'dragging') {
|
|
17979
|
-
hasScrolled.current = true;
|
|
17980
|
-
}
|
|
17981
|
-
},
|
|
17992
|
+
onPageScrollStateChanged: onPageScrollStateChanged,
|
|
17982
17993
|
onPageSelected: function onPageSelected(e) {
|
|
17983
17994
|
var index = e.nativeEvent.position;
|
|
17984
17995
|
var selectedItem = tabs[index];
|
|
@@ -18042,23 +18053,26 @@ var Tabs = function Tabs(_ref2) {
|
|
|
18042
18053
|
componentTestID = _ref2.testID;
|
|
18043
18054
|
var theme = useTheme$1();
|
|
18044
18055
|
var insets = reactNativeSafeAreaContext.useSafeAreaInsets();
|
|
18045
|
-
var pagerViewRef =
|
|
18056
|
+
var pagerViewRef = React.useRef(null);
|
|
18046
18057
|
var selectedTabIndex = tabs.findIndex(function (item) {
|
|
18047
18058
|
return item.key === selectedTabKey;
|
|
18048
18059
|
});
|
|
18049
|
-
var scrollOffsetAnimatedValue =
|
|
18050
|
-
var positionAnimatedValue =
|
|
18051
|
-
var
|
|
18052
|
-
|
|
18053
|
-
tabsWidth =
|
|
18054
|
-
setTabsWidth =
|
|
18060
|
+
var scrollOffsetAnimatedValue = React.useRef(new reactNative.Animated.Value(0)).current;
|
|
18061
|
+
var positionAnimatedValue = React.useRef(new reactNative.Animated.Value(0)).current;
|
|
18062
|
+
var _useState = React.useState(0),
|
|
18063
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
18064
|
+
tabsWidth = _useState2[0],
|
|
18065
|
+
setTabsWidth = _useState2[1];
|
|
18066
|
+
var _useHandlePageScroll = useHandlePageScroll(),
|
|
18067
|
+
onPageScrollStateChanged = _useHandlePageScroll.onPageScrollStateChanged,
|
|
18068
|
+
hasScrolled = _useHandlePageScroll.hasScrolled;
|
|
18055
18069
|
React.useEffect(function () {
|
|
18056
18070
|
if (selectedTabIndex !== -1) {
|
|
18057
18071
|
var _pagerViewRef$current;
|
|
18058
18072
|
(_pagerViewRef$current = pagerViewRef.current) === null || _pagerViewRef$current === void 0 || _pagerViewRef$current.setPage(selectedTabIndex);
|
|
18059
18073
|
}
|
|
18060
18074
|
}, [selectedTabIndex]);
|
|
18061
|
-
var tabContextProviderValue =
|
|
18075
|
+
var tabContextProviderValue = React.useMemo(function () {
|
|
18062
18076
|
return {
|
|
18063
18077
|
selectedTabKey: selectedTabKey
|
|
18064
18078
|
};
|
|
@@ -18114,10 +18128,11 @@ var Tabs = function Tabs(_ref2) {
|
|
|
18114
18128
|
onPageSelected: function onPageSelected(e) {
|
|
18115
18129
|
var index = e.nativeEvent.position;
|
|
18116
18130
|
var selectedItem = tabs[index];
|
|
18117
|
-
if (selectedItem) {
|
|
18131
|
+
if (hasScrolled.current && selectedItem) {
|
|
18118
18132
|
onTabPress(selectedItem.key);
|
|
18119
18133
|
}
|
|
18120
18134
|
},
|
|
18135
|
+
onPageScrollStateChanged: onPageScrollStateChanged,
|
|
18121
18136
|
onPageScroll: reactNative.Animated.event([{
|
|
18122
18137
|
nativeEvent: {
|
|
18123
18138
|
offset: scrollOffsetAnimatedValue,
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import React, { useRef } from 'react';
|
|
2
|
-
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
1
|
+
import React, { useEffect, useMemo, useRef } from 'react';
|
|
3
2
|
import PagerView from 'react-native-pager-view';
|
|
4
|
-
import {
|
|
3
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
5
4
|
import type { TabsProps } from '.';
|
|
6
5
|
import SceneView from './SceneView';
|
|
7
6
|
import ScrollableTabHeader from './ScrollableTabsHeader/ScrollableTabsHeader';
|
|
7
|
+
import { TabContainer } from './StyledScrollableTabs';
|
|
8
|
+
import useHandlePageScroll from './useHandlePageScroll';
|
|
8
9
|
import { ScreenContext, TabContext } from './useIsFocused';
|
|
9
10
|
|
|
10
11
|
export interface ScrollableTabProps extends TabsProps {
|
|
@@ -23,15 +24,15 @@ const ScrollableTab = ({
|
|
|
23
24
|
testID: componentTestID,
|
|
24
25
|
variant = 'highlighted',
|
|
25
26
|
}: ScrollableTabProps) => {
|
|
26
|
-
const pagerViewRef =
|
|
27
|
+
const pagerViewRef = useRef<PagerView>(null);
|
|
27
28
|
const insets = useSafeAreaInsets();
|
|
28
29
|
const selectedTabIndex = tabs.findIndex(
|
|
29
30
|
(item) => item.key === selectedTabKey
|
|
30
31
|
);
|
|
31
|
-
// Used as a flag to prevent calling onTabPress on initial render
|
|
32
|
-
const hasScrolled = useRef(false);
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
const { hasScrolled, onPageScrollStateChanged } = useHandlePageScroll();
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
35
36
|
let timeoutHandle: ReturnType<typeof setTimeout>;
|
|
36
37
|
if (selectedTabIndex !== -1) {
|
|
37
38
|
// If the selected tab is changed too quickly, the setPage is crashed and not work anymore
|
|
@@ -49,7 +50,7 @@ const ScrollableTab = ({
|
|
|
49
50
|
};
|
|
50
51
|
}, [selectedTabIndex, pagerViewRef]);
|
|
51
52
|
|
|
52
|
-
const tabContextProviderValue =
|
|
53
|
+
const tabContextProviderValue = useMemo(
|
|
53
54
|
() => ({
|
|
54
55
|
selectedTabKey,
|
|
55
56
|
}),
|
|
@@ -72,14 +73,7 @@ const ScrollableTab = ({
|
|
|
72
73
|
useNext
|
|
73
74
|
initialPage={selectedTabIndex}
|
|
74
75
|
ref={pagerViewRef}
|
|
75
|
-
onPageScrollStateChanged={
|
|
76
|
-
if (
|
|
77
|
-
!hasScrolled.current &&
|
|
78
|
-
e.nativeEvent.pageScrollState === 'dragging'
|
|
79
|
-
) {
|
|
80
|
-
hasScrolled.current = true;
|
|
81
|
-
}
|
|
82
|
-
}}
|
|
76
|
+
onPageScrollStateChanged={onPageScrollStateChanged}
|
|
83
77
|
onPageSelected={(e) => {
|
|
84
78
|
const index = e.nativeEvent.position;
|
|
85
79
|
const selectedItem = tabs[index];
|
|
@@ -99,6 +99,38 @@ describe('Tabs.Scroll', () => {
|
|
|
99
99
|
expect(getByText('Calendar Screen unfocused')).toBeDefined();
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
+
it('calls onTabPress correctly', () => {
|
|
103
|
+
const onTabPress = jest.fn();
|
|
104
|
+
const { getByText } = renderWithTheme(
|
|
105
|
+
<SafeAreaProvider
|
|
106
|
+
initialMetrics={{
|
|
107
|
+
frame: { x: 0, y: 0, width: 0, height: 0 },
|
|
108
|
+
insets: { top: 0, left: 0, right: 0, bottom: 0 },
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
<ScrollableTabs
|
|
112
|
+
tabs={[
|
|
113
|
+
{
|
|
114
|
+
key: 'work',
|
|
115
|
+
activeItem: 'Work',
|
|
116
|
+
component: <CustomScreen title="Work Screen" />,
|
|
117
|
+
},
|
|
118
|
+
]}
|
|
119
|
+
onTabPress={onTabPress}
|
|
120
|
+
selectedTabKey="work"
|
|
121
|
+
/>
|
|
122
|
+
</SafeAreaProvider>
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Not calling the function on first render
|
|
126
|
+
expect(onTabPress).not.toHaveBeenCalled();
|
|
127
|
+
|
|
128
|
+
// Calling the function on tab press
|
|
129
|
+
fireEvent.press(getByText('Work'));
|
|
130
|
+
|
|
131
|
+
expect(onTabPress).toHaveBeenCalledTimes(1);
|
|
132
|
+
});
|
|
133
|
+
|
|
102
134
|
describe('lazy', () => {
|
|
103
135
|
it('render all screens when lazy = false', async () => {
|
|
104
136
|
const { queryByText } = renderWithTheme(
|
|
@@ -110,6 +110,38 @@ describe('Tabs', () => {
|
|
|
110
110
|
fireEvent.press(getByText('Home'));
|
|
111
111
|
expect(getByText('Home Screen focused')).toBeDefined();
|
|
112
112
|
});
|
|
113
|
+
|
|
114
|
+
it('calls onTabPress only when pressed', () => {
|
|
115
|
+
const onTabPress = jest.fn();
|
|
116
|
+
const { getByText } = renderWithTheme(
|
|
117
|
+
<SafeAreaProvider
|
|
118
|
+
initialMetrics={{
|
|
119
|
+
frame: { x: 0, y: 0, width: 0, height: 0 },
|
|
120
|
+
insets: { top: 0, left: 0, right: 0, bottom: 0 },
|
|
121
|
+
}}
|
|
122
|
+
>
|
|
123
|
+
<Tabs
|
|
124
|
+
tabs={[
|
|
125
|
+
{
|
|
126
|
+
key: 'work',
|
|
127
|
+
activeItem: 'Work',
|
|
128
|
+
component: <CustomScreen title="Work Screen" />,
|
|
129
|
+
},
|
|
130
|
+
]}
|
|
131
|
+
onTabPress={onTabPress}
|
|
132
|
+
selectedTabKey="work"
|
|
133
|
+
/>
|
|
134
|
+
</SafeAreaProvider>
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// Not calling the function on first render
|
|
138
|
+
expect(onTabPress).not.toHaveBeenCalled();
|
|
139
|
+
|
|
140
|
+
// Calling the function on tab press
|
|
141
|
+
fireEvent.press(getByText('Work'));
|
|
142
|
+
|
|
143
|
+
expect(onTabPress).toHaveBeenCalledTimes(1);
|
|
144
|
+
});
|
|
113
145
|
});
|
|
114
146
|
|
|
115
147
|
describe('useIsFocused', () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useTheme } from '@emotion/react';
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
|
-
import React, { useEffect } from 'react';
|
|
3
|
+
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import type { StyleProp, ViewProps, ViewStyle } from 'react-native';
|
|
5
5
|
import { Animated, TouchableWithoutFeedback, View } from 'react-native';
|
|
6
6
|
import type { PagerViewOnPageScrollEventData } from 'react-native-pager-view';
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
} from './StyledTabs';
|
|
20
20
|
import type { BadgeConfigType } from './TabWithBadge';
|
|
21
21
|
import TabWithBadge from './TabWithBadge';
|
|
22
|
+
import useHandlePageScroll from './useHandlePageScroll';
|
|
22
23
|
import { ScreenContext, TabContext, useIsFocused } from './useIsFocused';
|
|
23
24
|
|
|
24
25
|
export type ItemType =
|
|
@@ -57,7 +58,7 @@ export interface TabsProps extends ViewProps {
|
|
|
57
58
|
*/
|
|
58
59
|
barStyle?: StyleProp<ViewStyle>;
|
|
59
60
|
/**
|
|
60
|
-
* Whether inactive screen should be removed and unmounted in
|
|
61
|
+
* Whether inactive screen should be removed and unmounted in
|
|
61
62
|
* Defaults value is `false`.
|
|
62
63
|
*/
|
|
63
64
|
lazy?: boolean;
|
|
@@ -116,13 +117,15 @@ const Tabs = ({
|
|
|
116
117
|
}: TabsProps): JSX.Element => {
|
|
117
118
|
const theme = useTheme();
|
|
118
119
|
const insets = useSafeAreaInsets();
|
|
119
|
-
const pagerViewRef =
|
|
120
|
+
const pagerViewRef = useRef<PagerView>(null);
|
|
120
121
|
const selectedTabIndex = tabs.findIndex(
|
|
121
122
|
(item) => item.key === selectedTabKey
|
|
122
123
|
);
|
|
123
|
-
const scrollOffsetAnimatedValue =
|
|
124
|
-
const positionAnimatedValue =
|
|
125
|
-
const [tabsWidth, setTabsWidth] =
|
|
124
|
+
const scrollOffsetAnimatedValue = useRef(new Animated.Value(0)).current;
|
|
125
|
+
const positionAnimatedValue = useRef(new Animated.Value(0)).current;
|
|
126
|
+
const [tabsWidth, setTabsWidth] = useState<number>(0);
|
|
127
|
+
|
|
128
|
+
const { onPageScrollStateChanged, hasScrolled } = useHandlePageScroll();
|
|
126
129
|
|
|
127
130
|
useEffect(() => {
|
|
128
131
|
if (selectedTabIndex !== -1) {
|
|
@@ -130,7 +133,7 @@ const Tabs = ({
|
|
|
130
133
|
}
|
|
131
134
|
}, [selectedTabIndex]);
|
|
132
135
|
|
|
133
|
-
const tabContextProviderValue =
|
|
136
|
+
const tabContextProviderValue = useMemo(
|
|
134
137
|
() => ({
|
|
135
138
|
selectedTabKey,
|
|
136
139
|
}),
|
|
@@ -201,10 +204,11 @@ const Tabs = ({
|
|
|
201
204
|
onPageSelected={(e) => {
|
|
202
205
|
const index = e.nativeEvent.position;
|
|
203
206
|
const selectedItem = tabs[index];
|
|
204
|
-
if (selectedItem) {
|
|
207
|
+
if (hasScrolled.current && selectedItem) {
|
|
205
208
|
onTabPress(selectedItem.key);
|
|
206
209
|
}
|
|
207
210
|
}}
|
|
211
|
+
onPageScrollStateChanged={onPageScrollStateChanged}
|
|
208
212
|
onPageScroll={Animated.event<PagerViewOnPageScrollEventData>(
|
|
209
213
|
[
|
|
210
214
|
{
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useCallback, useRef } from 'react';
|
|
2
|
+
import { NativeSyntheticEvent } from 'react-native';
|
|
3
|
+
|
|
4
|
+
const useHandlePageScroll = () => {
|
|
5
|
+
// Used as a flag to prevent calling onTabPress on initial render
|
|
6
|
+
const hasScrolled = useRef(false);
|
|
7
|
+
|
|
8
|
+
const onPageScrollStateChanged = useCallback(
|
|
9
|
+
(
|
|
10
|
+
e: NativeSyntheticEvent<
|
|
11
|
+
Readonly<{
|
|
12
|
+
pageScrollState: 'idle' | 'dragging' | 'settling';
|
|
13
|
+
}>
|
|
14
|
+
>
|
|
15
|
+
) => {
|
|
16
|
+
if (
|
|
17
|
+
!hasScrolled.current &&
|
|
18
|
+
e.nativeEvent.pageScrollState === 'dragging'
|
|
19
|
+
) {
|
|
20
|
+
hasScrolled.current = true;
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
[]
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
onPageScrollStateChanged,
|
|
28
|
+
hasScrolled,
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default useHandlePageScroll;
|