@hero-design/rn 8.63.3 → 8.63.4-alpha.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/es/index.js CHANGED
@@ -17827,6 +17827,20 @@ var ScrollableTabHeader = function ScrollableTabHeader(_ref2) {
17827
17827
  }));
17828
17828
  };
17829
17829
 
17830
+ var useHandlePageScroll = function useHandlePageScroll() {
17831
+ // Used as a flag to prevent calling onTabPress on initial render
17832
+ var hasScrolled = useRef(false);
17833
+ var onPageScrollStateChanged = useCallback(function (e) {
17834
+ if (!hasScrolled.current && e.nativeEvent.pageScrollState === 'dragging') {
17835
+ hasScrolled.current = true;
17836
+ }
17837
+ }, []);
17838
+ return {
17839
+ onPageScrollStateChanged: onPageScrollStateChanged,
17840
+ hasScrolled: hasScrolled
17841
+ };
17842
+ };
17843
+
17830
17844
  var TabContext = /*#__PURE__*/React__default.createContext(null);
17831
17845
  var ScreenContext = /*#__PURE__*/React__default.createContext(null);
17832
17846
  var useIsFocused = function useIsFocused() {
@@ -17854,14 +17868,15 @@ var ScrollableTab = function ScrollableTab(_ref) {
17854
17868
  componentTestID = _ref.testID,
17855
17869
  _ref$variant = _ref.variant,
17856
17870
  variant = _ref$variant === void 0 ? 'highlighted' : _ref$variant;
17857
- var pagerViewRef = React__default.useRef(null);
17871
+ var pagerViewRef = useRef(null);
17858
17872
  var insets = useSafeAreaInsets();
17859
17873
  var selectedTabIndex = tabs.findIndex(function (item) {
17860
17874
  return item.key === selectedTabKey;
17861
17875
  });
17862
- // Used as a flag to prevent calling onTabPress on initial render
17863
- var hasScrolled = useRef(false);
17864
- React__default.useEffect(function () {
17876
+ var _useHandlePageScroll = useHandlePageScroll(),
17877
+ hasScrolled = _useHandlePageScroll.hasScrolled,
17878
+ onPageScrollStateChanged = _useHandlePageScroll.onPageScrollStateChanged;
17879
+ useEffect(function () {
17865
17880
  var timeoutHandle;
17866
17881
  if (selectedTabIndex !== -1) {
17867
17882
  // If the selected tab is changed too quickly, the setPage is crashed and not work anymore
@@ -17878,7 +17893,7 @@ var ScrollableTab = function ScrollableTab(_ref) {
17878
17893
  }
17879
17894
  };
17880
17895
  }, [selectedTabIndex, pagerViewRef]);
17881
- var tabContextProviderValue = React__default.useMemo(function () {
17896
+ var tabContextProviderValue = useMemo(function () {
17882
17897
  return {
17883
17898
  selectedTabKey: selectedTabKey
17884
17899
  };
@@ -17900,11 +17915,7 @@ var ScrollableTab = function ScrollableTab(_ref) {
17900
17915
  useNext: true,
17901
17916
  initialPage: selectedTabIndex,
17902
17917
  ref: pagerViewRef,
17903
- onPageScrollStateChanged: function onPageScrollStateChanged(e) {
17904
- if (!hasScrolled.current && e.nativeEvent.pageScrollState === 'dragging') {
17905
- hasScrolled.current = true;
17906
- }
17907
- },
17918
+ onPageScrollStateChanged: onPageScrollStateChanged,
17908
17919
  onPageSelected: function onPageSelected(e) {
17909
17920
  var index = e.nativeEvent.position;
17910
17921
  var selectedItem = tabs[index];
@@ -17968,23 +17979,26 @@ var Tabs = function Tabs(_ref2) {
17968
17979
  componentTestID = _ref2.testID;
17969
17980
  var theme = useTheme$1();
17970
17981
  var insets = useSafeAreaInsets();
17971
- var pagerViewRef = React__default.useRef(null);
17982
+ var pagerViewRef = useRef(null);
17972
17983
  var selectedTabIndex = tabs.findIndex(function (item) {
17973
17984
  return item.key === selectedTabKey;
17974
17985
  });
17975
- var scrollOffsetAnimatedValue = React__default.useRef(new Animated.Value(0)).current;
17976
- var positionAnimatedValue = React__default.useRef(new Animated.Value(0)).current;
17977
- var _React$useState = React__default.useState(0),
17978
- _React$useState2 = _slicedToArray(_React$useState, 2),
17979
- tabsWidth = _React$useState2[0],
17980
- setTabsWidth = _React$useState2[1];
17986
+ var scrollOffsetAnimatedValue = useRef(new Animated.Value(0)).current;
17987
+ var positionAnimatedValue = useRef(new Animated.Value(0)).current;
17988
+ var _useState = useState(0),
17989
+ _useState2 = _slicedToArray(_useState, 2),
17990
+ tabsWidth = _useState2[0],
17991
+ setTabsWidth = _useState2[1];
17992
+ var _useHandlePageScroll = useHandlePageScroll(),
17993
+ onPageScrollStateChanged = _useHandlePageScroll.onPageScrollStateChanged,
17994
+ hasScrolled = _useHandlePageScroll.hasScrolled;
17981
17995
  useEffect(function () {
17982
17996
  if (selectedTabIndex !== -1) {
17983
17997
  var _pagerViewRef$current;
17984
17998
  (_pagerViewRef$current = pagerViewRef.current) === null || _pagerViewRef$current === void 0 || _pagerViewRef$current.setPage(selectedTabIndex);
17985
17999
  }
17986
18000
  }, [selectedTabIndex]);
17987
- var tabContextProviderValue = React__default.useMemo(function () {
18001
+ var tabContextProviderValue = useMemo(function () {
17988
18002
  return {
17989
18003
  selectedTabKey: selectedTabKey
17990
18004
  };
@@ -18040,10 +18054,11 @@ var Tabs = function Tabs(_ref2) {
18040
18054
  onPageSelected: function onPageSelected(e) {
18041
18055
  var index = e.nativeEvent.position;
18042
18056
  var selectedItem = tabs[index];
18043
- if (selectedItem) {
18057
+ if (hasScrolled.current && selectedItem) {
18044
18058
  onTabPress(selectedItem.key);
18045
18059
  }
18046
18060
  },
18061
+ onPageScrollStateChanged: onPageScrollStateChanged,
18047
18062
  onPageScroll: Animated.event([{
18048
18063
  nativeEvent: {
18049
18064
  offset: scrollOffsetAnimatedValue,
@@ -0,0 +1,42 @@
1
+ const heroDesign = require('@hero-design/eslint-plugin');
2
+ const _import = require('eslint-plugin-import');
3
+ const { FlatCompat } = require('@eslint/eslintrc');
4
+ const { includeIgnoreFile } = require('@eslint/compat');
5
+ const path = require('path');
6
+
7
+ const compat = new FlatCompat({
8
+ baseDirectory: __dirname,
9
+ });
10
+
11
+ const gitignorePath = path.resolve(__dirname, '../../.gitignore');
12
+
13
+ module.exports = [
14
+ ...compat.extends('hd', 'plugin:@hero-design/recommendedRn'),
15
+ includeIgnoreFile(gitignorePath),
16
+ {
17
+ files: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'],
18
+
19
+ plugins: {
20
+ '@hero-design': heroDesign,
21
+ import: _import,
22
+ },
23
+
24
+ languageOptions: {
25
+ parserOptions: {
26
+ tsconfigRootDir: __dirname,
27
+ project: ['./tsconfig.json'],
28
+ },
29
+ },
30
+
31
+ rules: {
32
+ 'no-underscore-dangle': [
33
+ 'error',
34
+ {
35
+ allow: ['__hd__'],
36
+ },
37
+ ],
38
+
39
+ 'import/no-cycle': 'error',
40
+ },
41
+ },
42
+ ];
package/lib/index.js CHANGED
@@ -17857,6 +17857,20 @@ var ScrollableTabHeader = function ScrollableTabHeader(_ref2) {
17857
17857
  }));
17858
17858
  };
17859
17859
 
17860
+ var useHandlePageScroll = function useHandlePageScroll() {
17861
+ // Used as a flag to prevent calling onTabPress on initial render
17862
+ var hasScrolled = React.useRef(false);
17863
+ var onPageScrollStateChanged = React.useCallback(function (e) {
17864
+ if (!hasScrolled.current && e.nativeEvent.pageScrollState === 'dragging') {
17865
+ hasScrolled.current = true;
17866
+ }
17867
+ }, []);
17868
+ return {
17869
+ onPageScrollStateChanged: onPageScrollStateChanged,
17870
+ hasScrolled: hasScrolled
17871
+ };
17872
+ };
17873
+
17860
17874
  var TabContext = /*#__PURE__*/React__default["default"].createContext(null);
17861
17875
  var ScreenContext = /*#__PURE__*/React__default["default"].createContext(null);
17862
17876
  var useIsFocused = function useIsFocused() {
@@ -17884,14 +17898,15 @@ var ScrollableTab = function ScrollableTab(_ref) {
17884
17898
  componentTestID = _ref.testID,
17885
17899
  _ref$variant = _ref.variant,
17886
17900
  variant = _ref$variant === void 0 ? 'highlighted' : _ref$variant;
17887
- var pagerViewRef = React__default["default"].useRef(null);
17901
+ var pagerViewRef = React.useRef(null);
17888
17902
  var insets = reactNativeSafeAreaContext.useSafeAreaInsets();
17889
17903
  var selectedTabIndex = tabs.findIndex(function (item) {
17890
17904
  return item.key === selectedTabKey;
17891
17905
  });
17892
- // Used as a flag to prevent calling onTabPress on initial render
17893
- var hasScrolled = React.useRef(false);
17894
- React__default["default"].useEffect(function () {
17906
+ var _useHandlePageScroll = useHandlePageScroll(),
17907
+ hasScrolled = _useHandlePageScroll.hasScrolled,
17908
+ onPageScrollStateChanged = _useHandlePageScroll.onPageScrollStateChanged;
17909
+ React.useEffect(function () {
17895
17910
  var timeoutHandle;
17896
17911
  if (selectedTabIndex !== -1) {
17897
17912
  // If the selected tab is changed too quickly, the setPage is crashed and not work anymore
@@ -17908,7 +17923,7 @@ var ScrollableTab = function ScrollableTab(_ref) {
17908
17923
  }
17909
17924
  };
17910
17925
  }, [selectedTabIndex, pagerViewRef]);
17911
- var tabContextProviderValue = React__default["default"].useMemo(function () {
17926
+ var tabContextProviderValue = React.useMemo(function () {
17912
17927
  return {
17913
17928
  selectedTabKey: selectedTabKey
17914
17929
  };
@@ -17930,11 +17945,7 @@ var ScrollableTab = function ScrollableTab(_ref) {
17930
17945
  useNext: true,
17931
17946
  initialPage: selectedTabIndex,
17932
17947
  ref: pagerViewRef,
17933
- onPageScrollStateChanged: function onPageScrollStateChanged(e) {
17934
- if (!hasScrolled.current && e.nativeEvent.pageScrollState === 'dragging') {
17935
- hasScrolled.current = true;
17936
- }
17937
- },
17948
+ onPageScrollStateChanged: onPageScrollStateChanged,
17938
17949
  onPageSelected: function onPageSelected(e) {
17939
17950
  var index = e.nativeEvent.position;
17940
17951
  var selectedItem = tabs[index];
@@ -17998,23 +18009,26 @@ var Tabs = function Tabs(_ref2) {
17998
18009
  componentTestID = _ref2.testID;
17999
18010
  var theme = useTheme$1();
18000
18011
  var insets = reactNativeSafeAreaContext.useSafeAreaInsets();
18001
- var pagerViewRef = React__default["default"].useRef(null);
18012
+ var pagerViewRef = React.useRef(null);
18002
18013
  var selectedTabIndex = tabs.findIndex(function (item) {
18003
18014
  return item.key === selectedTabKey;
18004
18015
  });
18005
- var scrollOffsetAnimatedValue = React__default["default"].useRef(new reactNative.Animated.Value(0)).current;
18006
- var positionAnimatedValue = React__default["default"].useRef(new reactNative.Animated.Value(0)).current;
18007
- var _React$useState = React__default["default"].useState(0),
18008
- _React$useState2 = _slicedToArray(_React$useState, 2),
18009
- tabsWidth = _React$useState2[0],
18010
- setTabsWidth = _React$useState2[1];
18016
+ var scrollOffsetAnimatedValue = React.useRef(new reactNative.Animated.Value(0)).current;
18017
+ var positionAnimatedValue = React.useRef(new reactNative.Animated.Value(0)).current;
18018
+ var _useState = React.useState(0),
18019
+ _useState2 = _slicedToArray(_useState, 2),
18020
+ tabsWidth = _useState2[0],
18021
+ setTabsWidth = _useState2[1];
18022
+ var _useHandlePageScroll = useHandlePageScroll(),
18023
+ onPageScrollStateChanged = _useHandlePageScroll.onPageScrollStateChanged,
18024
+ hasScrolled = _useHandlePageScroll.hasScrolled;
18011
18025
  React.useEffect(function () {
18012
18026
  if (selectedTabIndex !== -1) {
18013
18027
  var _pagerViewRef$current;
18014
18028
  (_pagerViewRef$current = pagerViewRef.current) === null || _pagerViewRef$current === void 0 || _pagerViewRef$current.setPage(selectedTabIndex);
18015
18029
  }
18016
18030
  }, [selectedTabIndex]);
18017
- var tabContextProviderValue = React__default["default"].useMemo(function () {
18031
+ var tabContextProviderValue = React.useMemo(function () {
18018
18032
  return {
18019
18033
  selectedTabKey: selectedTabKey
18020
18034
  };
@@ -18070,10 +18084,11 @@ var Tabs = function Tabs(_ref2) {
18070
18084
  onPageSelected: function onPageSelected(e) {
18071
18085
  var index = e.nativeEvent.position;
18072
18086
  var selectedItem = tabs[index];
18073
- if (selectedItem) {
18087
+ if (hasScrolled.current && selectedItem) {
18074
18088
  onTabPress(selectedItem.key);
18075
18089
  }
18076
18090
  },
18091
+ onPageScrollStateChanged: onPageScrollStateChanged,
18077
18092
  onPageScroll: reactNative.Animated.event([{
18078
18093
  nativeEvent: {
18079
18094
  offset: scrollOffsetAnimatedValue,
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@hero-design/rn",
3
- "version": "8.63.3",
3
+ "version": "8.63.4-alpha.0",
4
4
  "license": "MIT",
5
5
  "main": "lib/index.js",
6
6
  "module": "es/index.js",
7
7
  "types": "types/index.d.ts",
8
8
  "scripts": {
9
- "lint": "eslint src --ext .js,.jsx,.ts,.tsx --ignore-path ../../.gitignore",
9
+ "lint": "eslint src",
10
10
  "type-check": "tsc --noEmit",
11
11
  "test": "jest --runInBand",
12
12
  "test:watch": "jest --runInBand --watch",
@@ -47,7 +47,10 @@
47
47
  "@babel/preset-typescript": "^7.20.0",
48
48
  "@babel/runtime": "^7.20.0",
49
49
  "@emotion/jest": "^11.11.0",
50
- "@hero-design/eslint-plugin": "9.0.0",
50
+ "@eslint/compat": "^1.1.1",
51
+ "@eslint/eslintrc": "^3.1.0",
52
+ "@eslint/js": "^9.8.0",
53
+ "@hero-design/eslint-plugin": "9.0.1",
51
54
  "@hero-design/react-native-month-year-picker": "^8.42.10",
52
55
  "@react-native-community/datetimepicker": "7.6.1",
53
56
  "@react-native-community/slider": "^4.5.1",
@@ -86,6 +89,7 @@
86
89
  "rollup": "^2.68.0",
87
90
  "rollup-plugin-copy": "^3.4.0",
88
91
  "rollup-plugin-flow": "^1.1.1",
92
+ "rollup-plugin-visualizer": "^5.12.0",
89
93
  "ts-jest": "^29.1.1",
90
94
  "typescript": "4.8.4"
91
95
  },
package/rollup.config.js CHANGED
@@ -6,11 +6,16 @@ import json from '@rollup/plugin-json';
6
6
  import replace from '@rollup/plugin-replace';
7
7
  import copy from 'rollup-plugin-copy';
8
8
  import flow from 'rollup-plugin-flow';
9
+ import { visualizer } from 'rollup-plugin-visualizer';
9
10
 
10
11
  import pkg from './package.json';
11
12
 
12
13
  const extensions = ['.js', '.jsx', '.ts', '.tsx'];
13
14
 
15
+ const generateBuildStats = process.env.GENERATE_BUILD_STATS === 'true';
16
+ const bundleTemplate = process.env.BUNDLE_TEMPLATE || 'treemap';
17
+ const fileName = process.env.FILE_NAME || `stats/${pkg.version}/rn-stats.html`;
18
+
14
19
  export default {
15
20
  input: 'src/index.ts',
16
21
  output: [
@@ -54,5 +59,13 @@ export default {
54
59
  },
55
60
  ],
56
61
  }),
62
+ ...(generateBuildStats
63
+ ? [
64
+ visualizer({
65
+ filename: fileName,
66
+ template: bundleTemplate,
67
+ }),
68
+ ]
69
+ : []),
57
70
  ],
58
71
  };
@@ -6,6 +6,6 @@ sonar.organization=thinkei
6
6
 
7
7
  sonar.sources=.
8
8
  sonar.inclusions=**/*
9
- sonar.exclusions=**/__tests__/**,**/public/**
9
+ sonar.exclusions=**/__tests__/**,**/public/**,**/stats/**,**.config.js
10
10
  sonar.java.binaries=**/src/main/java
11
11
  sonar.javascript.lcov.reportPaths=./coverage/lcov.info
@@ -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 { TabContainer } from './StyledScrollableTabs';
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 = React.useRef<PagerView>(null);
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
- React.useEffect(() => {
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 = React.useMemo(
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={(e) => {
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 React.
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 = React.useRef<PagerView>(null);
120
+ const pagerViewRef = useRef<PagerView>(null);
120
121
  const selectedTabIndex = tabs.findIndex(
121
122
  (item) => item.key === selectedTabKey
122
123
  );
123
- const scrollOffsetAnimatedValue = React.useRef(new Animated.Value(0)).current;
124
- const positionAnimatedValue = React.useRef(new Animated.Value(0)).current;
125
- const [tabsWidth, setTabsWidth] = React.useState<number>(0);
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 = React.useMemo(
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;