@xsolla/xui-tab-bar 0.148.0 → 0.148.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/README.md +251 -0
- package/package.json +4 -4
package/README.md
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Tab Bar
|
|
2
|
+
|
|
3
|
+
A cross-platform React tab bar component implementing mobile-style bottom navigation, typically used with React Navigation. Follows WAI-ARIA Tabs pattern with proper keyboard navigation.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @xsolla/xui-tab-bar
|
|
9
|
+
# or
|
|
10
|
+
yarn add @xsolla/xui-tab-bar
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Demo
|
|
14
|
+
|
|
15
|
+
### Basic Tab Bar
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import * as React from 'react';
|
|
19
|
+
import { TabBar } from '@xsolla/xui-tab-bar';
|
|
20
|
+
import { Home, Search, User, Settings } from '@xsolla/xui-icons-base';
|
|
21
|
+
|
|
22
|
+
export default function BasicTabBar() {
|
|
23
|
+
// Simulated React Navigation state
|
|
24
|
+
const state = {
|
|
25
|
+
index: 0,
|
|
26
|
+
routes: [
|
|
27
|
+
{ key: 'home', name: 'Home' },
|
|
28
|
+
{ key: 'search', name: 'Search' },
|
|
29
|
+
{ key: 'profile', name: 'Profile' },
|
|
30
|
+
{ key: 'settings', name: 'Settings' },
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const descriptors = {
|
|
35
|
+
home: { options: { tabBarIcon: ({ size }) => <Home size={size} />, title: 'Home' } },
|
|
36
|
+
search: { options: { tabBarIcon: ({ size }) => <Search size={size} />, title: 'Search' } },
|
|
37
|
+
profile: { options: { tabBarIcon: ({ size }) => <User size={size} />, title: 'Profile' } },
|
|
38
|
+
settings: { options: { tabBarIcon: ({ size }) => <Settings size={size} />, title: 'Settings' } },
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<TabBar
|
|
43
|
+
state={state}
|
|
44
|
+
descriptors={descriptors}
|
|
45
|
+
navigation={{ emit: () => ({}), navigate: () => {} }}
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Anatomy
|
|
52
|
+
|
|
53
|
+
```jsx
|
|
54
|
+
import { TabBar } from '@xsolla/xui-tab-bar';
|
|
55
|
+
|
|
56
|
+
<TabBar
|
|
57
|
+
state={navigationState} // React Navigation state
|
|
58
|
+
descriptors={descriptors} // Route descriptors
|
|
59
|
+
navigation={navigation} // Navigation object
|
|
60
|
+
labelPosition="below-icon" // below-icon or beside-icon
|
|
61
|
+
backgroundColor={color} // Custom background
|
|
62
|
+
activateOnFocus={true} // Activate tab on focus
|
|
63
|
+
aria-label="Main navigation" // Accessible label
|
|
64
|
+
id="main-tabs" // Element ID
|
|
65
|
+
/>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Examples
|
|
69
|
+
|
|
70
|
+
### With React Navigation
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import * as React from 'react';
|
|
74
|
+
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
|
75
|
+
import { TabBar } from '@xsolla/xui-tab-bar';
|
|
76
|
+
import { Home, User, Settings } from '@xsolla/xui-icons-base';
|
|
77
|
+
|
|
78
|
+
const Tab = createBottomTabNavigator();
|
|
79
|
+
|
|
80
|
+
export default function AppNavigator() {
|
|
81
|
+
return (
|
|
82
|
+
<Tab.Navigator
|
|
83
|
+
tabBar={(props) => <TabBar {...props} />}
|
|
84
|
+
>
|
|
85
|
+
<Tab.Screen
|
|
86
|
+
name="Home"
|
|
87
|
+
component={HomeScreen}
|
|
88
|
+
options={{
|
|
89
|
+
tabBarIcon: ({ size, color }) => <Home size={size} color={color} />,
|
|
90
|
+
}}
|
|
91
|
+
/>
|
|
92
|
+
<Tab.Screen
|
|
93
|
+
name="Profile"
|
|
94
|
+
component={ProfileScreen}
|
|
95
|
+
options={{
|
|
96
|
+
tabBarIcon: ({ size, color }) => <User size={size} color={color} />,
|
|
97
|
+
}}
|
|
98
|
+
/>
|
|
99
|
+
<Tab.Screen
|
|
100
|
+
name="Settings"
|
|
101
|
+
component={SettingsScreen}
|
|
102
|
+
options={{
|
|
103
|
+
tabBarIcon: ({ size, color }) => <Settings size={size} color={color} />,
|
|
104
|
+
}}
|
|
105
|
+
/>
|
|
106
|
+
</Tab.Navigator>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### With Badges
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import * as React from 'react';
|
|
115
|
+
import { TabBar } from '@xsolla/xui-tab-bar';
|
|
116
|
+
import { Home, Bell, ShoppingCart, User } from '@xsolla/xui-icons-base';
|
|
117
|
+
|
|
118
|
+
export default function TabBarWithBadges() {
|
|
119
|
+
const state = {
|
|
120
|
+
index: 0,
|
|
121
|
+
routes: [
|
|
122
|
+
{ key: 'home', name: 'Home' },
|
|
123
|
+
{ key: 'notifications', name: 'Notifications' },
|
|
124
|
+
{ key: 'cart', name: 'Cart' },
|
|
125
|
+
{ key: 'profile', name: 'Profile' },
|
|
126
|
+
],
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const descriptors = {
|
|
130
|
+
home: { options: { tabBarIcon: ({ size }) => <Home size={size} />, title: 'Home' } },
|
|
131
|
+
notifications: {
|
|
132
|
+
options: {
|
|
133
|
+
tabBarIcon: ({ size }) => <Bell size={size} />,
|
|
134
|
+
title: 'Notifications',
|
|
135
|
+
tabBarBadge: 3, // Shows badge with count
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
cart: {
|
|
139
|
+
options: {
|
|
140
|
+
tabBarIcon: ({ size }) => <ShoppingCart size={size} />,
|
|
141
|
+
title: 'Cart',
|
|
142
|
+
tabBarBadge: '!', // Shows badge with text
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
profile: { options: { tabBarIcon: ({ size }) => <User size={size} />, title: 'Profile' } },
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<TabBar
|
|
150
|
+
state={state}
|
|
151
|
+
descriptors={descriptors}
|
|
152
|
+
navigation={{ emit: () => ({}), navigate: () => {} }}
|
|
153
|
+
/>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Custom Styling
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
import * as React from 'react';
|
|
162
|
+
import { TabBar } from '@xsolla/xui-tab-bar';
|
|
163
|
+
import { Home, Search, User } from '@xsolla/xui-icons-base';
|
|
164
|
+
|
|
165
|
+
export default function CustomStyledTabBar() {
|
|
166
|
+
const state = {
|
|
167
|
+
index: 0,
|
|
168
|
+
routes: [
|
|
169
|
+
{ key: 'home', name: 'Home' },
|
|
170
|
+
{ key: 'search', name: 'Search' },
|
|
171
|
+
{ key: 'profile', name: 'Profile' },
|
|
172
|
+
],
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const descriptors = {
|
|
176
|
+
home: { options: { tabBarIcon: ({ size }) => <Home size={size} />, title: 'Home' } },
|
|
177
|
+
search: { options: { tabBarIcon: ({ size }) => <Search size={size} />, title: 'Search' } },
|
|
178
|
+
profile: { options: { tabBarIcon: ({ size }) => <User size={size} />, title: 'Profile' } },
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
<TabBar
|
|
183
|
+
state={state}
|
|
184
|
+
descriptors={descriptors}
|
|
185
|
+
navigation={{ emit: () => ({}), navigate: () => {} }}
|
|
186
|
+
backgroundColor="#1a1a1a"
|
|
187
|
+
labelPosition="below-icon"
|
|
188
|
+
/>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## API Reference
|
|
194
|
+
|
|
195
|
+
### TabBar
|
|
196
|
+
|
|
197
|
+
**TabBarProps:**
|
|
198
|
+
|
|
199
|
+
| Prop | Type | Default | Description |
|
|
200
|
+
| :--- | :--- | :------ | :---------- |
|
|
201
|
+
| state | `NavigationState` | - | React Navigation state object. |
|
|
202
|
+
| descriptors | `Descriptors` | - | Route descriptor objects. |
|
|
203
|
+
| navigation | `Navigation` | - | Navigation object with emit/navigate. |
|
|
204
|
+
| labelPosition | `"below-icon" \| "beside-icon"` | `"below-icon"` | Label position relative to icon. |
|
|
205
|
+
| backgroundColor | `string` | theme background | Custom background color. |
|
|
206
|
+
| activateOnFocus | `boolean` | `true` | Navigate on focus (keyboard). |
|
|
207
|
+
| aria-label | `string` | `"Tab navigation"` | Accessible label. |
|
|
208
|
+
| aria-labelledby | `string` | - | ID of labelling element. |
|
|
209
|
+
| id | `string` | - | Element ID for accessibility. |
|
|
210
|
+
| testID | `string` | - | Test identifier. |
|
|
211
|
+
|
|
212
|
+
### Route Options
|
|
213
|
+
|
|
214
|
+
Each route in descriptors can have these options:
|
|
215
|
+
|
|
216
|
+
| Option | Type | Description |
|
|
217
|
+
| :----- | :--- | :---------- |
|
|
218
|
+
| tabBarIcon | `(props) => ReactNode` | Icon render function. |
|
|
219
|
+
| tabBarLabel | `string \| (props) => ReactNode` | Tab label. |
|
|
220
|
+
| title | `string` | Fallback label if tabBarLabel not set. |
|
|
221
|
+
| tabBarBadge | `string \| number` | Badge content. |
|
|
222
|
+
| tabBarShowLabel | `boolean` | Show/hide label. |
|
|
223
|
+
| tabBarAccessibilityLabel | `string` | Custom accessible label. |
|
|
224
|
+
| tabBarTestID | `string` | Test ID for individual tab. |
|
|
225
|
+
|
|
226
|
+
## Keyboard Navigation
|
|
227
|
+
|
|
228
|
+
| Key | Action |
|
|
229
|
+
| :-- | :----- |
|
|
230
|
+
| `ArrowRight` / `ArrowDown` | Move to next tab |
|
|
231
|
+
| `ArrowLeft` / `ArrowUp` | Move to previous tab |
|
|
232
|
+
| `Home` | Jump to first tab |
|
|
233
|
+
| `End` | Jump to last tab |
|
|
234
|
+
| `Enter` / `Space` | Activate focused tab |
|
|
235
|
+
|
|
236
|
+
## Specifications
|
|
237
|
+
|
|
238
|
+
| Property | Value |
|
|
239
|
+
| :------- | :---- |
|
|
240
|
+
| Height | 60px |
|
|
241
|
+
| Width | 100% |
|
|
242
|
+
| Border | 1px top border |
|
|
243
|
+
|
|
244
|
+
## Accessibility
|
|
245
|
+
|
|
246
|
+
- Uses `role="tablist"` with `aria-orientation="horizontal"`
|
|
247
|
+
- Individual tabs have `role="tab"` with proper `aria-selected`
|
|
248
|
+
- Keyboard navigation follows WAI-ARIA Tabs pattern
|
|
249
|
+
- Focus management between tabs
|
|
250
|
+
- Badge content is announced to screen readers
|
|
251
|
+
- Custom accessibility labels supported per tab
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xsolla/xui-tab-bar",
|
|
3
|
-
"version": "0.148.
|
|
3
|
+
"version": "0.148.1",
|
|
4
4
|
"main": "./web/index.js",
|
|
5
5
|
"module": "./web/index.mjs",
|
|
6
6
|
"types": "./web/index.d.ts",
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
"test:coverage": "vitest run --coverage"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@xsolla/xui-badge": "0.148.
|
|
17
|
-
"@xsolla/xui-core": "0.148.
|
|
18
|
-
"@xsolla/xui-primitives-core": "0.148.
|
|
16
|
+
"@xsolla/xui-badge": "0.148.1",
|
|
17
|
+
"@xsolla/xui-core": "0.148.1",
|
|
18
|
+
"@xsolla/xui-primitives-core": "0.148.1"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
21
21
|
"react": ">=16.8.0"
|