@orionarm/react-native-collapse-tabs 1.0.5 → 1.0.7
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/README.md +72 -39
- package/package.json +30 -10
package/README.md
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
# @orionarm/react-native-collapse-tabs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@orionarm/react-native-collapse-tabs)
|
|
4
|
+
[](https://www.npmjs.com/package/@orionarm/react-native-collapse-tabs)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
[]()
|
|
7
|
+
[](https://www.npmjs.com/package/@orionarm/react-native-collapse-tabs)
|
|
4
8
|
|
|
5
|
-
>
|
|
9
|
+
> A high-performance **React Native collapsible tabs** component with **sticky / animated header**, **swipeable pages**, and **per-tab scroll state**. Built on [`react-native-pager-view`](https://github.com/callstack/react-native-pager-view) and [`react-native-reanimated`](https://github.com/software-mansion/react-native-reanimated) v3.
|
|
10
|
+
|
|
11
|
+
## Preview
|
|
12
|
+
|
|
13
|
+
<p align="center">
|
|
14
|
+
<img src="https://raw.githubusercontent.com/orion-arm-ai/react-native-collapse-tabs/main/assets/collapse-tabs.gif" alt="collapse-tabs demo" width="320" />
|
|
15
|
+
</p>
|
|
6
16
|
|
|
7
17
|
---
|
|
8
18
|
|
|
@@ -12,7 +22,9 @@
|
|
|
12
22
|
- 🗂 **Swipeable tabs** — horizontal paging powered by `react-native-pager-view`.
|
|
13
23
|
- 🎚 **Per-tab scroll state** — each tab keeps its own scroll position.
|
|
14
24
|
- 🪄 **Animated tab switching** — header smoothly tweens between tabs (no sudden jumps).
|
|
25
|
+
- 🛡 **Overscroll-safe** — pull-to-refresh / bounce area won't push the header off screen.
|
|
15
26
|
- 🎨 **Custom header & tab bar** — bring your own UI, or use the built-in `DefaultTabBar`.
|
|
27
|
+
- 🪝 **`onScroll` passthrough** — wrapped lists still forward your own scroll handler (worklet or JS).
|
|
16
28
|
- ⚡ **Reanimated 3 worklets** — animations run on the UI thread for 60fps.
|
|
17
29
|
- 🧩 **Drop-in scrollables** — wrapped `FlatList` / `ScrollView` handle the plumbing for you.
|
|
18
30
|
|
|
@@ -20,13 +32,13 @@
|
|
|
20
32
|
|
|
21
33
|
## Requirements
|
|
22
34
|
|
|
23
|
-
| Peer dependency
|
|
24
|
-
|
|
|
25
|
-
| `react`
|
|
26
|
-
| `react-native`
|
|
27
|
-
| `react-native-gesture-handler
|
|
28
|
-
| `react-native-pager-view`
|
|
29
|
-
| `react-native-reanimated`
|
|
35
|
+
| Peer dependency | Version |
|
|
36
|
+
| ------------------------------ | ---------- |
|
|
37
|
+
| `react` | `>=16.8.0` |
|
|
38
|
+
| `react-native` | `>=0.60.0` |
|
|
39
|
+
| `react-native-gesture-handler` | `>=2.0.0` |
|
|
40
|
+
| `react-native-pager-view` | `>=6.0.0` |
|
|
41
|
+
| `react-native-reanimated` | `>=3.0.0` |
|
|
30
42
|
|
|
31
43
|
Make sure Reanimated is set up correctly (Babel plugin + `react-native-reanimated/plugin` at the **end** of your `babel.config.js` plugins array).
|
|
32
44
|
|
|
@@ -114,9 +126,18 @@ export default function Example() {
|
|
|
114
126
|
}
|
|
115
127
|
|
|
116
128
|
const styles = StyleSheet.create({
|
|
117
|
-
header: {
|
|
129
|
+
header: {
|
|
130
|
+
flex: 1,
|
|
131
|
+
backgroundColor: "#2D8CFF",
|
|
132
|
+
justifyContent: "center",
|
|
133
|
+
alignItems: "center",
|
|
134
|
+
},
|
|
118
135
|
headerText: { color: "#fff", fontSize: 22, fontWeight: "600" },
|
|
119
|
-
row: {
|
|
136
|
+
row: {
|
|
137
|
+
padding: 16,
|
|
138
|
+
borderBottomWidth: StyleSheet.hairlineWidth,
|
|
139
|
+
borderColor: "#eee",
|
|
140
|
+
},
|
|
120
141
|
});
|
|
121
142
|
```
|
|
122
143
|
|
|
@@ -130,41 +151,54 @@ const styles = StyleSheet.create({
|
|
|
130
151
|
|
|
131
152
|
The root container.
|
|
132
153
|
|
|
133
|
-
| Prop | Type
|
|
134
|
-
| ---------------------- |
|
|
135
|
-
| `headerHeight` | `number`
|
|
136
|
-
| `tabBarHeight` | `number`
|
|
137
|
-
| `children` | `TabReactElement \| TabReactElement[]`
|
|
138
|
-
| `initialTabName` | `string`
|
|
139
|
-
| `minHeaderHeight` | `number`
|
|
140
|
-
| `renderHeader` | `(props: HeaderProps) => ReactElement \| null`
|
|
141
|
-
| `renderTabBar` | `(props: TabBarProps) => ReactElement \| null`
|
|
142
|
-
| `containerStyle` | `StyleProp<ViewStyle>`
|
|
143
|
-
| `headerContainerStyle` | `StyleProp<ViewStyle>`
|
|
144
|
-
| `pagerProps` | `Omit<PagerViewProps, "onPageScroll" \| "initialPage">`
|
|
145
|
-
| `onIndexChange` | `(index: number) => void`
|
|
154
|
+
| Prop | Type | Required | Description |
|
|
155
|
+
| ---------------------- | ------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------- |
|
|
156
|
+
| `headerHeight` | `number` | ✅ | Fixed height of the header content (above the tab bar). |
|
|
157
|
+
| `tabBarHeight` | `number` | ✅ | Fixed height of the tab bar. |
|
|
158
|
+
| `children` | `TabReactElement \| TabReactElement[]` | ✅ | One or more `<Tab>` children. |
|
|
159
|
+
| `initialTabName` | `string` | | Tab to focus on mount. Defaults to the first child. |
|
|
160
|
+
| `minHeaderHeight` | `number` | | Minimum visible header height once collapsed. Default `0`. |
|
|
161
|
+
| `renderHeader` | `(props: HeaderProps) => ReactElement \| null` | | Render function for the header content. |
|
|
162
|
+
| `renderTabBar` | `(props: TabBarProps) => ReactElement \| null` | | Render function for a custom tab bar. Falls back to `<DefaultTabBar>` if not provided. |
|
|
163
|
+
| `containerStyle` | `StyleProp<ViewStyle>` | | Style for the outer container. |
|
|
164
|
+
| `headerContainerStyle` | `StyleProp<ViewStyle>` | | Style for the absolutely-positioned header wrapper. |
|
|
165
|
+
| `pagerProps` | `Omit<PagerViewProps, "onPageScroll" \| "initialPage">` | | Extra props forwarded to `PagerView`. |
|
|
166
|
+
| `onIndexChange` | `(index: number) => void` | | Fired after the focused tab changes. |
|
|
146
167
|
|
|
147
168
|
### `<Tab />`
|
|
148
169
|
|
|
149
170
|
Wraps a single tab's content. Should be a direct child of `<CollapseTabs>`.
|
|
150
171
|
|
|
151
|
-
| Prop | Type | Required | Description
|
|
152
|
-
| ---------- | ----------------- | -------- |
|
|
153
|
-
| `name` | `string` | ✅ | Unique identifier — must match the inner list's `name`.
|
|
172
|
+
| Prop | Type | Required | Description |
|
|
173
|
+
| ---------- | ----------------- | -------- | ---------------------------------------------------------------------- |
|
|
174
|
+
| `name` | `string` | ✅ | Unique identifier — must match the inner list's `name`. |
|
|
154
175
|
| `label` | `string` | | Optional display label (currently used by `DefaultTabBar` via `name`). |
|
|
155
|
-
| `children` | `React.ReactNode` | ✅ | Tab content — usually a wrapped `<FlatList>` or `<ScrollView>`.
|
|
176
|
+
| `children` | `React.ReactNode` | ✅ | Tab content — usually a wrapped `<FlatList>` or `<ScrollView>`. |
|
|
156
177
|
|
|
157
178
|
### `<FlatList />` and `<ScrollView />`
|
|
158
179
|
|
|
159
180
|
Drop-in replacements for the standard components, pre-wired to the collapse-tabs scroll system.
|
|
160
181
|
|
|
161
|
-
| Prop
|
|
162
|
-
|
|
|
163
|
-
| `name`
|
|
164
|
-
|
|
|
182
|
+
| Prop | Type | Required | Description |
|
|
183
|
+
| ---------- | --------------------------------------- | -------- | ----------------------------------------------------------------------------------- |
|
|
184
|
+
| `name` | `string` | ✅ | Must match the parent `<Tab name="..." />`. |
|
|
185
|
+
| `onScroll` | `(event) => void` or Reanimated worklet | | Forwarded after the internal handler runs. Works with both JS and worklet handlers. |
|
|
186
|
+
| ... | — | | All other standard `FlatList` / `ScrollView` props. |
|
|
165
187
|
|
|
166
188
|
> They automatically apply `paddingTop: headerHeight + tabBarHeight` to the content so your first item starts below the header.
|
|
167
189
|
|
|
190
|
+
```tsx
|
|
191
|
+
// Custom onScroll still works — gets called after the header math runs.
|
|
192
|
+
<FlatList
|
|
193
|
+
name="Posts"
|
|
194
|
+
data={data}
|
|
195
|
+
renderItem={renderItem}
|
|
196
|
+
onScroll={(e) => {
|
|
197
|
+
console.log("user scroll y =", e.nativeEvent.contentOffset.y);
|
|
198
|
+
}}
|
|
199
|
+
/>
|
|
200
|
+
```
|
|
201
|
+
|
|
168
202
|
### `<DefaultTabBar />`
|
|
169
203
|
|
|
170
204
|
A minimal built-in tab bar with a sliding underline indicator. Pass any custom UI through `renderTabBar` if you need something different.
|
|
@@ -179,11 +213,11 @@ const {
|
|
|
179
213
|
tabBarHeight,
|
|
180
214
|
headerScrollDistance,
|
|
181
215
|
tabNames,
|
|
182
|
-
index,
|
|
183
|
-
indexDecimal,
|
|
184
|
-
focusedTab,
|
|
185
|
-
scrollY,
|
|
186
|
-
headerTranslateY
|
|
216
|
+
index, // SharedValue<number>
|
|
217
|
+
indexDecimal, // SharedValue<number>
|
|
218
|
+
focusedTab, // SharedValue<string>
|
|
219
|
+
scrollY, // SharedValue<Record<string, number>>
|
|
220
|
+
headerTranslateY, // SharedValue<number>
|
|
187
221
|
containerRef,
|
|
188
222
|
} = useTabsContext();
|
|
189
223
|
```
|
|
@@ -234,11 +268,10 @@ import type {
|
|
|
234
268
|
|
|
235
269
|
## Roadmap
|
|
236
270
|
|
|
237
|
-
- [ ] Pull-to-refresh integration
|
|
238
271
|
- [ ] Dynamic header height
|
|
239
272
|
- [ ] SectionList / horizontal-list support
|
|
240
273
|
- [ ] Snap-to-collapse behavior
|
|
241
|
-
- [ ] Example app
|
|
274
|
+
- [ ] Example app
|
|
242
275
|
|
|
243
276
|
---
|
|
244
277
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orionarm/react-native-collapse-tabs",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "A React Native collapsible tabs component",
|
|
3
|
+
"version": "1.0.7",
|
|
4
|
+
"description": "A high-performance React Native collapsible tabs component with sticky/animated header, swipeable pages, and per-tab scroll. Built on react-native-pager-view and react-native-reanimated v3.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
@@ -12,18 +12,34 @@
|
|
|
12
12
|
},
|
|
13
13
|
"keywords": [
|
|
14
14
|
"react-native",
|
|
15
|
+
"react-native-tabs",
|
|
16
|
+
"react-native-collapsible-tabs",
|
|
17
|
+
"react-native-sticky-header",
|
|
18
|
+
"react-native-pager-view",
|
|
19
|
+
"react-native-reanimated",
|
|
15
20
|
"collapse",
|
|
16
|
-
"tabs",
|
|
17
21
|
"collapsible",
|
|
18
|
-
"
|
|
19
|
-
"react-component",
|
|
20
|
-
"react-native",
|
|
21
|
-
"ios",
|
|
22
|
-
"android",
|
|
22
|
+
"tabs",
|
|
23
23
|
"tab",
|
|
24
|
-
"
|
|
24
|
+
"tab-view",
|
|
25
|
+
"tabbar",
|
|
26
|
+
"tab-bar",
|
|
27
|
+
"sticky-header",
|
|
28
|
+
"sticky",
|
|
29
|
+
"animated-header",
|
|
30
|
+
"parallax-header",
|
|
31
|
+
"scroll",
|
|
25
32
|
"scrollable",
|
|
26
|
-
"
|
|
33
|
+
"swipe",
|
|
34
|
+
"swipeable",
|
|
35
|
+
"pager",
|
|
36
|
+
"pager-view",
|
|
37
|
+
"reanimated",
|
|
38
|
+
"ios",
|
|
39
|
+
"android",
|
|
40
|
+
"expo",
|
|
41
|
+
"flatlist",
|
|
42
|
+
"scrollview"
|
|
27
43
|
],
|
|
28
44
|
"author": "yanan_orionarm",
|
|
29
45
|
"license": "ISC",
|
|
@@ -35,6 +51,10 @@
|
|
|
35
51
|
"url": "https://github.com/orion-arm-ai/react-native-collapse-tabs/issues"
|
|
36
52
|
},
|
|
37
53
|
"homepage": "https://github.com/orion-arm-ai/react-native-collapse-tabs#readme",
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=16"
|
|
56
|
+
},
|
|
57
|
+
"sideEffects": false,
|
|
38
58
|
"peerDependencies": {
|
|
39
59
|
"react": ">=16.8.0",
|
|
40
60
|
"react-native": ">=0.60.0",
|