@hero-design/rn 8.115.1 → 8.116.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 +6 -0
- package/README.md +118 -0
- package/es/index.js +72 -43
- package/lib/index.js +72 -43
- package/package.json +1 -1
- package/sonar-project.properties +2 -2
- package/src/components/Tabs/ScrollableTabs.tsx +1 -1
- package/src/components/Tabs/index.tsx +118 -56
- package/types/components/Tabs/ScrollableTabs.d.ts +1 -1
- package/types/components/Tabs/index.d.ts +25 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @hero-design/rn
|
|
2
2
|
|
|
3
|
+
## 8.116.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#4647](https://github.com/Thinkei/hero-design/pull/4647) [`a5254d3e57528ec951ec233be9a1c6f6d9234a7b`](https://github.com/Thinkei/hero-design/commit/a5254d3e57528ec951ec233be9a1c6f6d9234a7b) Thanks [@cuongnguyeneh](https://github.com/cuongnguyeneh)! - feat: Add support for custom tab header
|
|
8
|
+
|
|
3
9
|
## 8.115.1
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/README.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# @hero-design/rn
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`@hero-design/rn` is a React Native component library built with TypeScript and Emotion. It provides UI components, theming system, chart components (D3.js), form components, mobile-specific components (FAB, BottomSheet, Swipeable), and platform-specific implementations (iOS/Android) following Hero Design's design system principles.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
yarn add @hero-design/rn
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Peer Dependencies:**
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
yarn add react@18.3.1 react-native@0.77.3
|
|
17
|
+
yarn add @hero-design/react-native-month-year-picker@^8.43.2
|
|
18
|
+
yarn add @ptomasroos/react-native-multi-slider@^2.2.2
|
|
19
|
+
yarn add @react-native-community/datetimepicker@^3.5.2
|
|
20
|
+
yarn add @react-native-community/slider@^4.5.1
|
|
21
|
+
yarn add react-native-gesture-handler@~2.20.2
|
|
22
|
+
yarn add react-native-linear-gradient@^2.8.3
|
|
23
|
+
yarn add react-native-pager-view@^6.7.0
|
|
24
|
+
yarn add react-native-safe-area-context@^4.7.0
|
|
25
|
+
yarn add react-native-svg@^15.11.2
|
|
26
|
+
yarn add react-native-vector-icons@^9.1.0
|
|
27
|
+
yarn add react-native-webview@^13.10.2
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Requirements:**
|
|
31
|
+
- React 18.3.1
|
|
32
|
+
- React Native 0.77.3
|
|
33
|
+
- Node.js >= 20.0.0 (20.19.5 recommended)
|
|
34
|
+
- Yarn >= 4.0.2 (enabled via Corepack: `corepack enable`)
|
|
35
|
+
- iOS Simulator or Android Emulator:
|
|
36
|
+
- **For visual tests compatibility**: iPhone 14 (iOS 18+) or Android Pixel 6 (API 30) are recommended
|
|
37
|
+
- **For non-visual fixes or demo purposes**: Any device frame with compatible OS version is sufficient
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
### Basic Setup
|
|
42
|
+
|
|
43
|
+
Wrap your application with `HeroDesignProvider` to enable theming, localization, and component features (Toast, Portal):
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import React from 'react';
|
|
47
|
+
import { HeroDesignProvider, getTheme, Button, Card, Typography } from '@hero-design/rn';
|
|
48
|
+
|
|
49
|
+
function App() {
|
|
50
|
+
const theme = getTheme();
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<HeroDesignProvider theme={theme}>
|
|
54
|
+
<Card>
|
|
55
|
+
<Typography.Title>Welcome to Hero Design</Typography.Title>
|
|
56
|
+
<Button text="Get Started" intent="primary" onPress={() => {}} />
|
|
57
|
+
</Card>
|
|
58
|
+
</HeroDesignProvider>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Theming
|
|
64
|
+
|
|
65
|
+
Hero Design React Native uses a powerful theming system built on Emotion.
|
|
66
|
+
|
|
67
|
+
### Using ThemeSwitcher
|
|
68
|
+
|
|
69
|
+
For product-specific themes, use `ThemeSwitcher` which provides a predefined theme. Available theme names: `ehWork`, `ehJobs`, `ehWorkDark`.
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import { ThemeSwitcher } from '@hero-design/rn';
|
|
73
|
+
|
|
74
|
+
function App() {
|
|
75
|
+
return (
|
|
76
|
+
<ThemeSwitcher name="ehWork">
|
|
77
|
+
{/* Your app */}
|
|
78
|
+
</ThemeSwitcher>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Note:** `ThemeSwitcher` only provides theme. For Toast, Portal, and Locale features, use `HeroDesignProvider` with a theme from `getTheme()`.
|
|
84
|
+
|
|
85
|
+
### Design Tokens
|
|
86
|
+
|
|
87
|
+
The theme includes semantic design tokens organized by category:
|
|
88
|
+
|
|
89
|
+
- **Colors**: Global colors (`defaultGlobalSurface`, `onDefaultGlobalSurface`, etc.) and brand colors (`primary`, `secondary`, etc.)
|
|
90
|
+
- **Typography**: `theme.fontSizes`, `theme.fonts`, `theme.lineHeights`
|
|
91
|
+
- **Spacing**: `theme.space` - Consistent spacing scale (`small`, `medium`, `large`, etc.)
|
|
92
|
+
- **Shadows**: `theme.shadows` - Elevation and depth
|
|
93
|
+
- **Components**: Component-specific theme configurations via `theme.__hd__`
|
|
94
|
+
|
|
95
|
+
For comprehensive design token documentation, visit the [Mobile Design Tokens](https://design.employmenthero.com/mobile/mobile-design-tokens).
|
|
96
|
+
|
|
97
|
+
## Examples
|
|
98
|
+
|
|
99
|
+
For comprehensive examples and component documentation:
|
|
100
|
+
|
|
101
|
+
- **Documentation Site**: Visit the [Hero Design documentation site](https://design.employmenthero.com/mobile/intro)
|
|
102
|
+
- **Mobile Playground**: Explore the [rn-playground](https://github.com/Thinkei/hero-design/tree/master/apps/rn-playground)
|
|
103
|
+
|
|
104
|
+
## Contributing
|
|
105
|
+
|
|
106
|
+
Contributions to `@hero-design/rn` are welcome!
|
|
107
|
+
|
|
108
|
+
To get started:
|
|
109
|
+
|
|
110
|
+
1. Clone the repository: `git clone git@github.com:Thinkei/hero-design.git`
|
|
111
|
+
2. Enable Corepack: `corepack enable`
|
|
112
|
+
3. Install dependencies: `yarn install`
|
|
113
|
+
4. Build the package: `yarn turbo run build --filter=@hero-design/rn`
|
|
114
|
+
5. Run the playground: `yarn dev:rn`
|
|
115
|
+
|
|
116
|
+
**Note:** An Expo account is required to start the playground. Contact the Hero Design team for access.
|
|
117
|
+
|
|
118
|
+
For detailed contributing guidelines, see the main repository [Contributing documentation](https://design.employmenthero.com/mobile/Contributing/coContribution).
|
package/es/index.js
CHANGED
|
@@ -28030,51 +28030,19 @@ var getTabItem = function getTabItem(_ref) {
|
|
|
28030
28030
|
color: color
|
|
28031
28031
|
});
|
|
28032
28032
|
};
|
|
28033
|
-
var
|
|
28034
|
-
var
|
|
28033
|
+
var TabsHeader = function TabsHeader(_ref2) {
|
|
28034
|
+
var tabs = _ref2.tabs,
|
|
28035
28035
|
selectedTabKey = _ref2.selectedTabKey,
|
|
28036
|
-
|
|
28037
|
-
containerStyle = _ref2.containerStyle,
|
|
28036
|
+
onTabPress = _ref2.onTabPress,
|
|
28038
28037
|
barStyle = _ref2.barStyle,
|
|
28039
|
-
|
|
28040
|
-
|
|
28041
|
-
|
|
28042
|
-
|
|
28043
|
-
|
|
28044
|
-
|
|
28045
|
-
componentTestID = _ref2.testID;
|
|
28038
|
+
insets = _ref2.insets,
|
|
28039
|
+
componentTestID = _ref2.componentTestID,
|
|
28040
|
+
tabsWidth = _ref2.tabsWidth,
|
|
28041
|
+
setTabsWidth = _ref2.setTabsWidth,
|
|
28042
|
+
positionAnimatedValue = _ref2.positionAnimatedValue,
|
|
28043
|
+
scrollOffsetAnimatedValue = _ref2.scrollOffsetAnimatedValue;
|
|
28046
28044
|
var theme = useTheme$1();
|
|
28047
|
-
|
|
28048
|
-
var pagerViewRef = useRef(null);
|
|
28049
|
-
var selectedTabIndex = tabs.findIndex(function (item) {
|
|
28050
|
-
return item.key === selectedTabKey;
|
|
28051
|
-
});
|
|
28052
|
-
var scrollOffsetAnimatedValue = useRef(new Animated.Value(0)).current;
|
|
28053
|
-
var positionAnimatedValue = useRef(new Animated.Value(0)).current;
|
|
28054
|
-
var _useState = useState(0),
|
|
28055
|
-
_useState2 = _slicedToArray(_useState, 2),
|
|
28056
|
-
tabsWidth = _useState2[0],
|
|
28057
|
-
setTabsWidth = _useState2[1];
|
|
28058
|
-
var _useHandlePageScroll = useHandlePageScroll(),
|
|
28059
|
-
onPageScrollStateChanged = _useHandlePageScroll.onPageScrollStateChanged,
|
|
28060
|
-
hasScrolled = _useHandlePageScroll.hasScrolled;
|
|
28061
|
-
useEffect(function () {
|
|
28062
|
-
if (selectedTabIndex !== -1) {
|
|
28063
|
-
var _pagerViewRef$current;
|
|
28064
|
-
(_pagerViewRef$current = pagerViewRef.current) === null || _pagerViewRef$current === void 0 || _pagerViewRef$current.setPage(selectedTabIndex);
|
|
28065
|
-
}
|
|
28066
|
-
}, [selectedTabIndex]);
|
|
28067
|
-
var tabContextProviderValue = useMemo(function () {
|
|
28068
|
-
return {
|
|
28069
|
-
selectedTabKey: selectedTabKey
|
|
28070
|
-
};
|
|
28071
|
-
}, [selectedTabKey]);
|
|
28072
|
-
return /*#__PURE__*/React__default.createElement(TabContext.Provider, {
|
|
28073
|
-
value: tabContextProviderValue
|
|
28074
|
-
}, /*#__PURE__*/React__default.createElement(TabContainer$1, {
|
|
28075
|
-
style: containerStyle,
|
|
28076
|
-
testID: componentTestID
|
|
28077
|
-
}, /*#__PURE__*/React__default.createElement(HeaderTabWrapper$1, {
|
|
28045
|
+
return /*#__PURE__*/React__default.createElement(HeaderTabWrapper$1, {
|
|
28078
28046
|
themeInsets: insets,
|
|
28079
28047
|
style: barStyle,
|
|
28080
28048
|
testID: componentTestID ? "".concat(componentTestID, "-tab-bar") : undefined
|
|
@@ -28113,7 +28081,67 @@ var Tabs = function Tabs(_ref2) {
|
|
|
28113
28081
|
scrollOffsetAnimatedValue: scrollOffsetAnimatedValue,
|
|
28114
28082
|
tabsLength: tabs.length,
|
|
28115
28083
|
tabsWidth: tabsWidth
|
|
28116
|
-
})))
|
|
28084
|
+
})));
|
|
28085
|
+
};
|
|
28086
|
+
var Tabs = function Tabs(_ref3) {
|
|
28087
|
+
var onTabPress = _ref3.onTabPress,
|
|
28088
|
+
selectedTabKey = _ref3.selectedTabKey,
|
|
28089
|
+
tabs = _ref3.tabs,
|
|
28090
|
+
containerStyle = _ref3.containerStyle,
|
|
28091
|
+
barStyle = _ref3.barStyle,
|
|
28092
|
+
_ref3$lazy = _ref3.lazy,
|
|
28093
|
+
lazy = _ref3$lazy === void 0 ? false : _ref3$lazy,
|
|
28094
|
+
_ref3$lazyPreloadDist = _ref3.lazyPreloadDistance,
|
|
28095
|
+
lazyPreloadDistance = _ref3$lazyPreloadDist === void 0 ? 1 : _ref3$lazyPreloadDist,
|
|
28096
|
+
_ref3$swipeEnabled = _ref3.swipeEnabled,
|
|
28097
|
+
swipeEnabled = _ref3$swipeEnabled === void 0 ? true : _ref3$swipeEnabled,
|
|
28098
|
+
componentTestID = _ref3.testID,
|
|
28099
|
+
header = _ref3.header;
|
|
28100
|
+
var insets = useSafeAreaInsets();
|
|
28101
|
+
var pagerViewRef = useRef(null);
|
|
28102
|
+
var selectedTabIndex = tabs.findIndex(function (item) {
|
|
28103
|
+
return item.key === selectedTabKey;
|
|
28104
|
+
});
|
|
28105
|
+
var scrollOffsetAnimatedValue = useRef(new Animated.Value(0)).current;
|
|
28106
|
+
var positionAnimatedValue = useRef(new Animated.Value(0)).current;
|
|
28107
|
+
var _useState = useState(0),
|
|
28108
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
28109
|
+
tabsWidth = _useState2[0],
|
|
28110
|
+
setTabsWidth = _useState2[1];
|
|
28111
|
+
var _useHandlePageScroll = useHandlePageScroll(),
|
|
28112
|
+
onPageScrollStateChanged = _useHandlePageScroll.onPageScrollStateChanged,
|
|
28113
|
+
hasScrolled = _useHandlePageScroll.hasScrolled;
|
|
28114
|
+
useEffect(function () {
|
|
28115
|
+
if (selectedTabIndex !== -1) {
|
|
28116
|
+
var _pagerViewRef$current;
|
|
28117
|
+
(_pagerViewRef$current = pagerViewRef.current) === null || _pagerViewRef$current === void 0 || _pagerViewRef$current.setPage(selectedTabIndex);
|
|
28118
|
+
}
|
|
28119
|
+
}, [selectedTabIndex]);
|
|
28120
|
+
var tabContextProviderValue = useMemo(function () {
|
|
28121
|
+
return {
|
|
28122
|
+
selectedTabKey: selectedTabKey
|
|
28123
|
+
};
|
|
28124
|
+
}, [selectedTabKey]);
|
|
28125
|
+
var headerProps = useMemo(function () {
|
|
28126
|
+
return {
|
|
28127
|
+
tabs: tabs,
|
|
28128
|
+
selectedTabKey: selectedTabKey,
|
|
28129
|
+
onTabPress: onTabPress,
|
|
28130
|
+
barStyle: barStyle,
|
|
28131
|
+
insets: insets,
|
|
28132
|
+
componentTestID: componentTestID,
|
|
28133
|
+
tabsWidth: tabsWidth,
|
|
28134
|
+
setTabsWidth: setTabsWidth,
|
|
28135
|
+
positionAnimatedValue: positionAnimatedValue,
|
|
28136
|
+
scrollOffsetAnimatedValue: scrollOffsetAnimatedValue
|
|
28137
|
+
};
|
|
28138
|
+
}, [tabs, selectedTabKey, onTabPress, barStyle, insets, componentTestID, tabsWidth, setTabsWidth, positionAnimatedValue, scrollOffsetAnimatedValue]);
|
|
28139
|
+
return /*#__PURE__*/React__default.createElement(TabContext.Provider, {
|
|
28140
|
+
value: tabContextProviderValue
|
|
28141
|
+
}, /*#__PURE__*/React__default.createElement(TabContainer$1, {
|
|
28142
|
+
style: containerStyle,
|
|
28143
|
+
testID: componentTestID
|
|
28144
|
+
}, header ? header(headerProps) : /*#__PURE__*/React__default.createElement(TabsHeader, headerProps), /*#__PURE__*/React__default.createElement(AnimatedPagerView, {
|
|
28117
28145
|
initialPage: selectedTabIndex,
|
|
28118
28146
|
ref: pagerViewRef,
|
|
28119
28147
|
onPageSelected: function onPageSelected(e) {
|
|
@@ -28154,6 +28182,7 @@ var Tabs = function Tabs(_ref2) {
|
|
|
28154
28182
|
}))));
|
|
28155
28183
|
};
|
|
28156
28184
|
var index$2 = Object.assign(Tabs, {
|
|
28185
|
+
Header: TabsHeader,
|
|
28157
28186
|
Scroll: ScrollableTab,
|
|
28158
28187
|
ScrollHeader: ScrollableTabHeader,
|
|
28159
28188
|
useIsFocused: useIsFocused
|
package/lib/index.js
CHANGED
|
@@ -28059,51 +28059,19 @@ var getTabItem = function getTabItem(_ref) {
|
|
|
28059
28059
|
color: color
|
|
28060
28060
|
});
|
|
28061
28061
|
};
|
|
28062
|
-
var
|
|
28063
|
-
var
|
|
28062
|
+
var TabsHeader = function TabsHeader(_ref2) {
|
|
28063
|
+
var tabs = _ref2.tabs,
|
|
28064
28064
|
selectedTabKey = _ref2.selectedTabKey,
|
|
28065
|
-
|
|
28066
|
-
containerStyle = _ref2.containerStyle,
|
|
28065
|
+
onTabPress = _ref2.onTabPress,
|
|
28067
28066
|
barStyle = _ref2.barStyle,
|
|
28068
|
-
|
|
28069
|
-
|
|
28070
|
-
|
|
28071
|
-
|
|
28072
|
-
|
|
28073
|
-
|
|
28074
|
-
componentTestID = _ref2.testID;
|
|
28067
|
+
insets = _ref2.insets,
|
|
28068
|
+
componentTestID = _ref2.componentTestID,
|
|
28069
|
+
tabsWidth = _ref2.tabsWidth,
|
|
28070
|
+
setTabsWidth = _ref2.setTabsWidth,
|
|
28071
|
+
positionAnimatedValue = _ref2.positionAnimatedValue,
|
|
28072
|
+
scrollOffsetAnimatedValue = _ref2.scrollOffsetAnimatedValue;
|
|
28075
28073
|
var theme = useTheme$1();
|
|
28076
|
-
|
|
28077
|
-
var pagerViewRef = React.useRef(null);
|
|
28078
|
-
var selectedTabIndex = tabs.findIndex(function (item) {
|
|
28079
|
-
return item.key === selectedTabKey;
|
|
28080
|
-
});
|
|
28081
|
-
var scrollOffsetAnimatedValue = React.useRef(new reactNative.Animated.Value(0)).current;
|
|
28082
|
-
var positionAnimatedValue = React.useRef(new reactNative.Animated.Value(0)).current;
|
|
28083
|
-
var _useState = React.useState(0),
|
|
28084
|
-
_useState2 = _slicedToArray(_useState, 2),
|
|
28085
|
-
tabsWidth = _useState2[0],
|
|
28086
|
-
setTabsWidth = _useState2[1];
|
|
28087
|
-
var _useHandlePageScroll = useHandlePageScroll(),
|
|
28088
|
-
onPageScrollStateChanged = _useHandlePageScroll.onPageScrollStateChanged,
|
|
28089
|
-
hasScrolled = _useHandlePageScroll.hasScrolled;
|
|
28090
|
-
React.useEffect(function () {
|
|
28091
|
-
if (selectedTabIndex !== -1) {
|
|
28092
|
-
var _pagerViewRef$current;
|
|
28093
|
-
(_pagerViewRef$current = pagerViewRef.current) === null || _pagerViewRef$current === void 0 || _pagerViewRef$current.setPage(selectedTabIndex);
|
|
28094
|
-
}
|
|
28095
|
-
}, [selectedTabIndex]);
|
|
28096
|
-
var tabContextProviderValue = React.useMemo(function () {
|
|
28097
|
-
return {
|
|
28098
|
-
selectedTabKey: selectedTabKey
|
|
28099
|
-
};
|
|
28100
|
-
}, [selectedTabKey]);
|
|
28101
|
-
return /*#__PURE__*/React__namespace.default.createElement(TabContext.Provider, {
|
|
28102
|
-
value: tabContextProviderValue
|
|
28103
|
-
}, /*#__PURE__*/React__namespace.default.createElement(TabContainer$1, {
|
|
28104
|
-
style: containerStyle,
|
|
28105
|
-
testID: componentTestID
|
|
28106
|
-
}, /*#__PURE__*/React__namespace.default.createElement(HeaderTabWrapper$1, {
|
|
28074
|
+
return /*#__PURE__*/React__namespace.default.createElement(HeaderTabWrapper$1, {
|
|
28107
28075
|
themeInsets: insets,
|
|
28108
28076
|
style: barStyle,
|
|
28109
28077
|
testID: componentTestID ? "".concat(componentTestID, "-tab-bar") : undefined
|
|
@@ -28142,7 +28110,67 @@ var Tabs = function Tabs(_ref2) {
|
|
|
28142
28110
|
scrollOffsetAnimatedValue: scrollOffsetAnimatedValue,
|
|
28143
28111
|
tabsLength: tabs.length,
|
|
28144
28112
|
tabsWidth: tabsWidth
|
|
28145
|
-
})))
|
|
28113
|
+
})));
|
|
28114
|
+
};
|
|
28115
|
+
var Tabs = function Tabs(_ref3) {
|
|
28116
|
+
var onTabPress = _ref3.onTabPress,
|
|
28117
|
+
selectedTabKey = _ref3.selectedTabKey,
|
|
28118
|
+
tabs = _ref3.tabs,
|
|
28119
|
+
containerStyle = _ref3.containerStyle,
|
|
28120
|
+
barStyle = _ref3.barStyle,
|
|
28121
|
+
_ref3$lazy = _ref3.lazy,
|
|
28122
|
+
lazy = _ref3$lazy === void 0 ? false : _ref3$lazy,
|
|
28123
|
+
_ref3$lazyPreloadDist = _ref3.lazyPreloadDistance,
|
|
28124
|
+
lazyPreloadDistance = _ref3$lazyPreloadDist === void 0 ? 1 : _ref3$lazyPreloadDist,
|
|
28125
|
+
_ref3$swipeEnabled = _ref3.swipeEnabled,
|
|
28126
|
+
swipeEnabled = _ref3$swipeEnabled === void 0 ? true : _ref3$swipeEnabled,
|
|
28127
|
+
componentTestID = _ref3.testID,
|
|
28128
|
+
header = _ref3.header;
|
|
28129
|
+
var insets = reactNativeSafeAreaContext.useSafeAreaInsets();
|
|
28130
|
+
var pagerViewRef = React.useRef(null);
|
|
28131
|
+
var selectedTabIndex = tabs.findIndex(function (item) {
|
|
28132
|
+
return item.key === selectedTabKey;
|
|
28133
|
+
});
|
|
28134
|
+
var scrollOffsetAnimatedValue = React.useRef(new reactNative.Animated.Value(0)).current;
|
|
28135
|
+
var positionAnimatedValue = React.useRef(new reactNative.Animated.Value(0)).current;
|
|
28136
|
+
var _useState = React.useState(0),
|
|
28137
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
28138
|
+
tabsWidth = _useState2[0],
|
|
28139
|
+
setTabsWidth = _useState2[1];
|
|
28140
|
+
var _useHandlePageScroll = useHandlePageScroll(),
|
|
28141
|
+
onPageScrollStateChanged = _useHandlePageScroll.onPageScrollStateChanged,
|
|
28142
|
+
hasScrolled = _useHandlePageScroll.hasScrolled;
|
|
28143
|
+
React.useEffect(function () {
|
|
28144
|
+
if (selectedTabIndex !== -1) {
|
|
28145
|
+
var _pagerViewRef$current;
|
|
28146
|
+
(_pagerViewRef$current = pagerViewRef.current) === null || _pagerViewRef$current === void 0 || _pagerViewRef$current.setPage(selectedTabIndex);
|
|
28147
|
+
}
|
|
28148
|
+
}, [selectedTabIndex]);
|
|
28149
|
+
var tabContextProviderValue = React.useMemo(function () {
|
|
28150
|
+
return {
|
|
28151
|
+
selectedTabKey: selectedTabKey
|
|
28152
|
+
};
|
|
28153
|
+
}, [selectedTabKey]);
|
|
28154
|
+
var headerProps = React.useMemo(function () {
|
|
28155
|
+
return {
|
|
28156
|
+
tabs: tabs,
|
|
28157
|
+
selectedTabKey: selectedTabKey,
|
|
28158
|
+
onTabPress: onTabPress,
|
|
28159
|
+
barStyle: barStyle,
|
|
28160
|
+
insets: insets,
|
|
28161
|
+
componentTestID: componentTestID,
|
|
28162
|
+
tabsWidth: tabsWidth,
|
|
28163
|
+
setTabsWidth: setTabsWidth,
|
|
28164
|
+
positionAnimatedValue: positionAnimatedValue,
|
|
28165
|
+
scrollOffsetAnimatedValue: scrollOffsetAnimatedValue
|
|
28166
|
+
};
|
|
28167
|
+
}, [tabs, selectedTabKey, onTabPress, barStyle, insets, componentTestID, tabsWidth, setTabsWidth, positionAnimatedValue, scrollOffsetAnimatedValue]);
|
|
28168
|
+
return /*#__PURE__*/React__namespace.default.createElement(TabContext.Provider, {
|
|
28169
|
+
value: tabContextProviderValue
|
|
28170
|
+
}, /*#__PURE__*/React__namespace.default.createElement(TabContainer$1, {
|
|
28171
|
+
style: containerStyle,
|
|
28172
|
+
testID: componentTestID
|
|
28173
|
+
}, header ? header(headerProps) : /*#__PURE__*/React__namespace.default.createElement(TabsHeader, headerProps), /*#__PURE__*/React__namespace.default.createElement(AnimatedPagerView, {
|
|
28146
28174
|
initialPage: selectedTabIndex,
|
|
28147
28175
|
ref: pagerViewRef,
|
|
28148
28176
|
onPageSelected: function onPageSelected(e) {
|
|
@@ -28183,6 +28211,7 @@ var Tabs = function Tabs(_ref2) {
|
|
|
28183
28211
|
}))));
|
|
28184
28212
|
};
|
|
28185
28213
|
var index$2 = Object.assign(Tabs, {
|
|
28214
|
+
Header: TabsHeader,
|
|
28186
28215
|
Scroll: ScrollableTab,
|
|
28187
28216
|
ScrollHeader: ScrollableTabHeader,
|
|
28188
28217
|
useIsFocused: useIsFocused
|
package/package.json
CHANGED
package/sonar-project.properties
CHANGED
|
@@ -4,6 +4,6 @@ sonar.organization=thinkei
|
|
|
4
4
|
|
|
5
5
|
sonar.sources=.
|
|
6
6
|
sonar.inclusions=**/*
|
|
7
|
-
sonar.exclusions=**/__tests__/**,**/public/**,**/stats/**,**.config.js,**/testUtils/**
|
|
7
|
+
sonar.exclusions=**/__tests__/**,**/public/**,**/stats/**,**.config.js,**/testUtils/**,**/lcov-report/**
|
|
8
8
|
sonar.java.binaries=**/src/main/java
|
|
9
|
-
sonar.javascript.lcov.reportPaths
|
|
9
|
+
sonar.javascript.lcov.reportPaths=rn-test-results*/lcov.info
|
|
@@ -10,7 +10,7 @@ import { TabContainer } from './StyledScrollableTabs';
|
|
|
10
10
|
import useHandlePageScroll from './useHandlePageScroll';
|
|
11
11
|
import { ScreenContext, TabContext } from './useIsFocused';
|
|
12
12
|
|
|
13
|
-
export interface ScrollableTabProps extends TabsProps {
|
|
13
|
+
export interface ScrollableTabProps extends Omit<TabsProps, 'header'> {
|
|
14
14
|
variant?: 'underlined' | 'highlighted';
|
|
15
15
|
header?: FunctionComponent<ScrollableTabHeaderProps>;
|
|
16
16
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useTheme } from '@emotion/react';
|
|
2
|
-
import type { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import type { FunctionComponent, ReactElement, ReactNode } from 'react';
|
|
3
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';
|
|
@@ -37,6 +37,18 @@ export type TabType = {
|
|
|
37
37
|
badge?: BadgeConfigType;
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
+
export interface TabsHeaderProps {
|
|
41
|
+
tabs: TabType[];
|
|
42
|
+
selectedTabKey: string;
|
|
43
|
+
onTabPress: (key: string) => void;
|
|
44
|
+
barStyle?: StyleProp<ViewStyle>;
|
|
45
|
+
insets: { top: number; right: number; bottom: number; left: number };
|
|
46
|
+
componentTestID?: string;
|
|
47
|
+
tabsWidth: number;
|
|
48
|
+
setTabsWidth: (width: number) => void;
|
|
49
|
+
positionAnimatedValue: Animated.Value;
|
|
50
|
+
scrollOffsetAnimatedValue: Animated.Value;
|
|
51
|
+
}
|
|
40
52
|
export interface TabsProps extends ViewProps {
|
|
41
53
|
/**
|
|
42
54
|
* Callback which is called on tab press, receiving key of upcoming active Tab.
|
|
@@ -77,6 +89,10 @@ export interface TabsProps extends ViewProps {
|
|
|
77
89
|
* Testing id of the component.
|
|
78
90
|
*/
|
|
79
91
|
testID?: string;
|
|
92
|
+
/**
|
|
93
|
+
* Custom header component.
|
|
94
|
+
*/
|
|
95
|
+
header?: FunctionComponent<TabsHeaderProps>;
|
|
80
96
|
}
|
|
81
97
|
|
|
82
98
|
const AnimatedPagerView = Animated.createAnimatedComponent(PagerView);
|
|
@@ -105,6 +121,77 @@ const getTabItem = ({
|
|
|
105
121
|
return item({ color });
|
|
106
122
|
};
|
|
107
123
|
|
|
124
|
+
const TabsHeader = ({
|
|
125
|
+
tabs,
|
|
126
|
+
selectedTabKey,
|
|
127
|
+
onTabPress,
|
|
128
|
+
barStyle,
|
|
129
|
+
insets,
|
|
130
|
+
componentTestID,
|
|
131
|
+
tabsWidth,
|
|
132
|
+
setTabsWidth,
|
|
133
|
+
positionAnimatedValue,
|
|
134
|
+
scrollOffsetAnimatedValue,
|
|
135
|
+
}: TabsHeaderProps) => {
|
|
136
|
+
const theme = useTheme();
|
|
137
|
+
return (
|
|
138
|
+
<HeaderTabWrapper
|
|
139
|
+
themeInsets={insets}
|
|
140
|
+
style={barStyle}
|
|
141
|
+
testID={componentTestID ? `${componentTestID}-tab-bar` : undefined}
|
|
142
|
+
>
|
|
143
|
+
<View>
|
|
144
|
+
<HeaderTab
|
|
145
|
+
onLayout={(e) => {
|
|
146
|
+
const { width } = e.nativeEvent.layout;
|
|
147
|
+
if (tabsWidth !== width) {
|
|
148
|
+
setTabsWidth(width);
|
|
149
|
+
}
|
|
150
|
+
}}
|
|
151
|
+
>
|
|
152
|
+
{tabs.map((tab) => {
|
|
153
|
+
const {
|
|
154
|
+
key,
|
|
155
|
+
testID,
|
|
156
|
+
activeItem,
|
|
157
|
+
inactiveItem: originalInactiveItem,
|
|
158
|
+
badge,
|
|
159
|
+
} = tab;
|
|
160
|
+
|
|
161
|
+
const active = selectedTabKey === key;
|
|
162
|
+
const inactiveItem = originalInactiveItem ?? activeItem;
|
|
163
|
+
const tabItem = getTabItem({
|
|
164
|
+
item: active ? activeItem : inactiveItem,
|
|
165
|
+
color: theme.__hd__.tabs.colors.text,
|
|
166
|
+
active,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
return (
|
|
170
|
+
<TouchableWithoutFeedback
|
|
171
|
+
key={key}
|
|
172
|
+
onPress={() => {
|
|
173
|
+
onTabPress(key);
|
|
174
|
+
}}
|
|
175
|
+
testID={testID}
|
|
176
|
+
>
|
|
177
|
+
<HeaderTabItem>
|
|
178
|
+
<TabWithBadge config={badge} tabItem={tabItem} />
|
|
179
|
+
</HeaderTabItem>
|
|
180
|
+
</TouchableWithoutFeedback>
|
|
181
|
+
);
|
|
182
|
+
})}
|
|
183
|
+
</HeaderTab>
|
|
184
|
+
<ActiveTabIndicator
|
|
185
|
+
positionAnimatedValue={positionAnimatedValue}
|
|
186
|
+
scrollOffsetAnimatedValue={scrollOffsetAnimatedValue}
|
|
187
|
+
tabsLength={tabs.length}
|
|
188
|
+
tabsWidth={tabsWidth}
|
|
189
|
+
/>
|
|
190
|
+
</View>
|
|
191
|
+
</HeaderTabWrapper>
|
|
192
|
+
);
|
|
193
|
+
};
|
|
194
|
+
|
|
108
195
|
const Tabs = ({
|
|
109
196
|
onTabPress,
|
|
110
197
|
selectedTabKey,
|
|
@@ -115,8 +202,8 @@ const Tabs = ({
|
|
|
115
202
|
lazyPreloadDistance = 1,
|
|
116
203
|
swipeEnabled = true,
|
|
117
204
|
testID: componentTestID,
|
|
205
|
+
header,
|
|
118
206
|
}: TabsProps): ReactElement => {
|
|
119
|
-
const theme = useTheme();
|
|
120
207
|
const insets = useSafeAreaInsets();
|
|
121
208
|
const pagerViewRef = useRef<PagerView>(null);
|
|
122
209
|
const selectedTabIndex = tabs.findIndex(
|
|
@@ -141,63 +228,37 @@ const Tabs = ({
|
|
|
141
228
|
[selectedTabKey]
|
|
142
229
|
);
|
|
143
230
|
|
|
231
|
+
const headerProps = useMemo(
|
|
232
|
+
() => ({
|
|
233
|
+
tabs,
|
|
234
|
+
selectedTabKey,
|
|
235
|
+
onTabPress,
|
|
236
|
+
barStyle,
|
|
237
|
+
insets,
|
|
238
|
+
componentTestID,
|
|
239
|
+
tabsWidth,
|
|
240
|
+
setTabsWidth,
|
|
241
|
+
positionAnimatedValue,
|
|
242
|
+
scrollOffsetAnimatedValue,
|
|
243
|
+
}),
|
|
244
|
+
[
|
|
245
|
+
tabs,
|
|
246
|
+
selectedTabKey,
|
|
247
|
+
onTabPress,
|
|
248
|
+
barStyle,
|
|
249
|
+
insets,
|
|
250
|
+
componentTestID,
|
|
251
|
+
tabsWidth,
|
|
252
|
+
setTabsWidth,
|
|
253
|
+
positionAnimatedValue,
|
|
254
|
+
scrollOffsetAnimatedValue,
|
|
255
|
+
]
|
|
256
|
+
);
|
|
257
|
+
|
|
144
258
|
return (
|
|
145
259
|
<TabContext.Provider value={tabContextProviderValue}>
|
|
146
260
|
<TabContainer style={containerStyle} testID={componentTestID}>
|
|
147
|
-
<
|
|
148
|
-
themeInsets={insets}
|
|
149
|
-
style={barStyle}
|
|
150
|
-
testID={componentTestID ? `${componentTestID}-tab-bar` : undefined}
|
|
151
|
-
>
|
|
152
|
-
<View>
|
|
153
|
-
<HeaderTab
|
|
154
|
-
onLayout={(e) => {
|
|
155
|
-
const { width } = e.nativeEvent.layout;
|
|
156
|
-
if (tabsWidth !== width) {
|
|
157
|
-
setTabsWidth(width);
|
|
158
|
-
}
|
|
159
|
-
}}
|
|
160
|
-
>
|
|
161
|
-
{tabs.map((tab) => {
|
|
162
|
-
const {
|
|
163
|
-
key,
|
|
164
|
-
testID,
|
|
165
|
-
activeItem,
|
|
166
|
-
inactiveItem: originalInactiveItem,
|
|
167
|
-
badge,
|
|
168
|
-
} = tab;
|
|
169
|
-
|
|
170
|
-
const active = selectedTabKey === key;
|
|
171
|
-
const inactiveItem = originalInactiveItem ?? activeItem;
|
|
172
|
-
const tabItem = getTabItem({
|
|
173
|
-
item: active ? activeItem : inactiveItem,
|
|
174
|
-
color: theme.__hd__.tabs.colors.text,
|
|
175
|
-
active,
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
return (
|
|
179
|
-
<TouchableWithoutFeedback
|
|
180
|
-
key={key}
|
|
181
|
-
onPress={() => {
|
|
182
|
-
onTabPress(key);
|
|
183
|
-
}}
|
|
184
|
-
testID={testID}
|
|
185
|
-
>
|
|
186
|
-
<HeaderTabItem>
|
|
187
|
-
<TabWithBadge config={badge} tabItem={tabItem} />
|
|
188
|
-
</HeaderTabItem>
|
|
189
|
-
</TouchableWithoutFeedback>
|
|
190
|
-
);
|
|
191
|
-
})}
|
|
192
|
-
</HeaderTab>
|
|
193
|
-
<ActiveTabIndicator
|
|
194
|
-
positionAnimatedValue={positionAnimatedValue}
|
|
195
|
-
scrollOffsetAnimatedValue={scrollOffsetAnimatedValue}
|
|
196
|
-
tabsLength={tabs.length}
|
|
197
|
-
tabsWidth={tabsWidth}
|
|
198
|
-
/>
|
|
199
|
-
</View>
|
|
200
|
-
</HeaderTabWrapper>
|
|
261
|
+
{header ? header(headerProps) : <TabsHeader {...headerProps} />}
|
|
201
262
|
<AnimatedPagerView
|
|
202
263
|
initialPage={selectedTabIndex}
|
|
203
264
|
ref={pagerViewRef}
|
|
@@ -250,6 +311,7 @@ const Tabs = ({
|
|
|
250
311
|
};
|
|
251
312
|
|
|
252
313
|
export default Object.assign(Tabs, {
|
|
314
|
+
Header: TabsHeader,
|
|
253
315
|
Scroll: ScrollableTabs,
|
|
254
316
|
ScrollHeader: ScrollableTabHeader,
|
|
255
317
|
useIsFocused,
|
|
@@ -2,7 +2,7 @@ import type { FunctionComponent } from 'react';
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import type { TabsProps } from '.';
|
|
4
4
|
import type { ScrollableTabHeaderProps } from './ScrollableTabsHeader/ScrollableTabsHeader';
|
|
5
|
-
export interface ScrollableTabProps extends TabsProps {
|
|
5
|
+
export interface ScrollableTabProps extends Omit<TabsProps, 'header'> {
|
|
6
6
|
variant?: 'underlined' | 'highlighted';
|
|
7
7
|
header?: FunctionComponent<ScrollableTabHeaderProps>;
|
|
8
8
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { ReactElement, ReactNode } from 'react';
|
|
1
|
+
import type { FunctionComponent, ReactElement, ReactNode } from 'react';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import type { StyleProp, ViewProps, ViewStyle } from 'react-native';
|
|
4
|
+
import { Animated } from 'react-native';
|
|
4
5
|
import type { IconName } from '../Icon';
|
|
5
6
|
import type { BadgeConfigType } from './TabWithBadge';
|
|
6
7
|
export type ItemType = string | IconName | ((props: {
|
|
@@ -14,6 +15,23 @@ export type TabType = {
|
|
|
14
15
|
testID?: string;
|
|
15
16
|
badge?: BadgeConfigType;
|
|
16
17
|
};
|
|
18
|
+
export interface TabsHeaderProps {
|
|
19
|
+
tabs: TabType[];
|
|
20
|
+
selectedTabKey: string;
|
|
21
|
+
onTabPress: (key: string) => void;
|
|
22
|
+
barStyle?: StyleProp<ViewStyle>;
|
|
23
|
+
insets: {
|
|
24
|
+
top: number;
|
|
25
|
+
right: number;
|
|
26
|
+
bottom: number;
|
|
27
|
+
left: number;
|
|
28
|
+
};
|
|
29
|
+
componentTestID?: string;
|
|
30
|
+
tabsWidth: number;
|
|
31
|
+
setTabsWidth: (width: number) => void;
|
|
32
|
+
positionAnimatedValue: Animated.Value;
|
|
33
|
+
scrollOffsetAnimatedValue: Animated.Value;
|
|
34
|
+
}
|
|
17
35
|
export interface TabsProps extends ViewProps {
|
|
18
36
|
/**
|
|
19
37
|
* Callback which is called on tab press, receiving key of upcoming active Tab.
|
|
@@ -54,8 +72,13 @@ export interface TabsProps extends ViewProps {
|
|
|
54
72
|
* Testing id of the component.
|
|
55
73
|
*/
|
|
56
74
|
testID?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Custom header component.
|
|
77
|
+
*/
|
|
78
|
+
header?: FunctionComponent<TabsHeaderProps>;
|
|
57
79
|
}
|
|
58
|
-
declare const _default: (({ onTabPress, selectedTabKey, tabs, containerStyle, barStyle, lazy, lazyPreloadDistance, swipeEnabled, testID: componentTestID, }: TabsProps) => ReactElement) & {
|
|
80
|
+
declare const _default: (({ onTabPress, selectedTabKey, tabs, containerStyle, barStyle, lazy, lazyPreloadDistance, swipeEnabled, testID: componentTestID, header, }: TabsProps) => ReactElement) & {
|
|
81
|
+
Header: ({ tabs, selectedTabKey, onTabPress, barStyle, insets, componentTestID, tabsWidth, setTabsWidth, positionAnimatedValue, scrollOffsetAnimatedValue, }: TabsHeaderProps) => React.JSX.Element;
|
|
59
82
|
Scroll: ({ onTabPress, selectedTabKey, tabs, containerStyle, barStyle, lazy, lazyPreloadDistance, swipeEnabled, testID: componentTestID, variant, header, }: import("./ScrollableTabs").ScrollableTabProps) => React.JSX.Element;
|
|
60
83
|
ScrollHeader: ({ onTabPress, selectedIndex, tabs, barStyle, testID, insets, variant, }: import("./ScrollableTabsHeader/ScrollableTabsHeader").ScrollableTabHeaderProps) => React.JSX.Element;
|
|
61
84
|
useIsFocused: () => boolean | undefined;
|