@xsolla/xui-tab-bar 0.149.1 → 0.151.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.
Files changed (2) hide show
  1. package/README.md +63 -117
  2. package/package.json +4 -4
package/README.md CHANGED
@@ -1,26 +1,27 @@
1
- # Tab Bar
1
+ # TabBar
2
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.
3
+ A pill-shaped, segmented-style tab bar that adapts the React Navigation bottom-tab API. Implements the WAI-ARIA Tabs pattern with roving tab index and arrow-key navigation.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
8
  npm install @xsolla/xui-tab-bar
9
- # or
10
- yarn add @xsolla/xui-tab-bar
11
9
  ```
12
10
 
13
- ## Demo
11
+ ## Imports
14
12
 
15
- ### Basic Tab Bar
13
+ ```tsx
14
+ import { TabBar, TabBarItem } from '@xsolla/xui-tab-bar';
15
+ ```
16
+
17
+ ## Quick start
16
18
 
17
19
  ```tsx
18
20
  import * as React from 'react';
19
21
  import { TabBar } from '@xsolla/xui-tab-bar';
20
22
  import { Home, Search, User, Settings } from '@xsolla/xui-icons-base';
21
23
 
22
- export default function BasicTabBar() {
23
- // Simulated React Navigation state
24
+ export default function Example() {
24
25
  const state = {
25
26
  index: 0,
26
27
  routes: [
@@ -43,31 +44,50 @@ export default function BasicTabBar() {
43
44
  state={state}
44
45
  descriptors={descriptors}
45
46
  navigation={{ emit: () => ({}), navigate: () => {} }}
47
+ aria-label="Main navigation"
46
48
  />
47
49
  );
48
50
  }
49
51
  ```
50
52
 
51
- ## Anatomy
53
+ ## API Reference
52
54
 
53
- ```jsx
54
- import { TabBar } from '@xsolla/xui-tab-bar';
55
+ ### `<TabBar>`
55
56
 
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
- ```
57
+ | Prop | Type | Default | Description |
58
+ | --- | --- | --- | --- |
59
+ | `state` | `{ index: number; routes: { key: string; name: string; params?: object }[] }` | - | React Navigation state. Required. |
60
+ | `descriptors` | `Record<string, { options: TabBarRouteOptions }>` | - | Per-route options keyed by `route.key`. Required. |
61
+ | `navigation` | `{ navigate: (name, params?) => void; emit: (opts) => any }` | - | React Navigation navigation object. Required. |
62
+ | `labelPosition` | `'below-icon' \| 'beside-icon'` | `'below-icon'` | Label position relative to icon. |
63
+ | `backgroundColor` | `string` | segmented-control bg token | Container background colour. |
64
+ | `activateOnFocus` | `boolean` | `true` | Activate a tab as soon as it receives keyboard focus. When `false`, arrow keys only move focus and Enter/Space activates. |
65
+ | `aria-label` | `string` | `'Tab navigation'` | Accessible label for the tablist. |
66
+ | `aria-labelledby` | `string` | - | ID of an external labelling element. |
67
+ | `id` | `string` | - | Container ID; used to derive per-tab IDs. |
68
+ | `testID` | `string` | `'tab-bar-container'` | Test identifier. |
69
+
70
+ Inherits `ThemeOverrideProps` (`themeMode`, `themeProductContext`).
71
+
72
+ #### Route options (per descriptor)
73
+
74
+ | Option | Type | Description |
75
+ | --- | --- | --- |
76
+ | `tabBarIcon` | `(props: { focused, color, size }) => ReactNode` | Icon render function. Called with `size={24}`. |
77
+ | `tabBarLabel` | `string \| ((props: { focused, color, position }) => ReactNode)` | Label override. |
78
+ | `title` | `string` | Fallback label when `tabBarLabel` is unset. |
79
+ | `tabBarBadge` | `string \| number` | Badge content rendered top-right of the icon. |
80
+ | `tabBarShowLabel` | `boolean` | Set `false` to hide the label. |
81
+ | `tabBarAccessibilityLabel` | `string` | Override per-tab accessible label. |
82
+ | `tabBarTestID` | `string` | Per-tab test identifier. |
83
+
84
+ ### `<TabBarItem>`
85
+
86
+ Lower-level item; usually rendered for you by `<TabBar>`. Exported for custom layouts. Accepts `label`, `icon`, `badge`, `focused`, `onPress`, `onLongPress`, `labelPosition`, `accessibilityLabel`, `index`, `tabCount`, plus refs and `testID`. Inherits `ThemeOverrideProps`.
67
87
 
68
88
  ## Examples
69
89
 
70
- ### With React Navigation
90
+ ### React Navigation integration
71
91
 
72
92
  ```tsx
73
93
  import * as React from 'react';
@@ -79,43 +99,35 @@ const Tab = createBottomTabNavigator();
79
99
 
80
100
  export default function AppNavigator() {
81
101
  return (
82
- <Tab.Navigator
83
- tabBar={(props) => <TabBar {...props} />}
84
- >
102
+ <Tab.Navigator tabBar={(props) => <TabBar {...props} aria-label="Main" />}>
85
103
  <Tab.Screen
86
104
  name="Home"
87
105
  component={HomeScreen}
88
- options={{
89
- tabBarIcon: ({ size, color }) => <Home size={size} color={color} />,
90
- }}
106
+ options={{ tabBarIcon: ({ size, color }) => <Home size={size} color={color} /> }}
91
107
  />
92
108
  <Tab.Screen
93
109
  name="Profile"
94
110
  component={ProfileScreen}
95
- options={{
96
- tabBarIcon: ({ size, color }) => <User size={size} color={color} />,
97
- }}
111
+ options={{ tabBarIcon: ({ size, color }) => <User size={size} color={color} /> }}
98
112
  />
99
113
  <Tab.Screen
100
114
  name="Settings"
101
115
  component={SettingsScreen}
102
- options={{
103
- tabBarIcon: ({ size, color }) => <Settings size={size} color={color} />,
104
- }}
116
+ options={{ tabBarIcon: ({ size, color }) => <Settings size={size} color={color} /> }}
105
117
  />
106
118
  </Tab.Navigator>
107
119
  );
108
120
  }
109
121
  ```
110
122
 
111
- ### With Badges
123
+ ### With badges
112
124
 
113
125
  ```tsx
114
126
  import * as React from 'react';
115
127
  import { TabBar } from '@xsolla/xui-tab-bar';
116
128
  import { Home, Bell, ShoppingCart, User } from '@xsolla/xui-icons-base';
117
129
 
118
- export default function TabBarWithBadges() {
130
+ export default function Example() {
119
131
  const state = {
120
132
  index: 0,
121
133
  routes: [
@@ -132,14 +144,14 @@ export default function TabBarWithBadges() {
132
144
  options: {
133
145
  tabBarIcon: ({ size }) => <Bell size={size} />,
134
146
  title: 'Notifications',
135
- tabBarBadge: 3, // Shows badge with count
147
+ tabBarBadge: 3,
136
148
  },
137
149
  },
138
150
  cart: {
139
151
  options: {
140
152
  tabBarIcon: ({ size }) => <ShoppingCart size={size} />,
141
153
  title: 'Cart',
142
- tabBarBadge: '!', // Shows badge with text
154
+ tabBarBadge: '!',
143
155
  },
144
156
  },
145
157
  profile: { options: { tabBarIcon: ({ size }) => <User size={size} />, title: 'Profile' } },
@@ -155,97 +167,31 @@ export default function TabBarWithBadges() {
155
167
  }
156
168
  ```
157
169
 
158
- ### Custom Styling
170
+ ### Manual focus activation
171
+
172
+ Set `activateOnFocus={false}` to require Enter or Space to commit a selection — useful when activation has side effects.
159
173
 
160
174
  ```tsx
161
175
  import * as React from 'react';
162
176
  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
177
 
178
+ export default function Example({ state, descriptors, navigation }) {
181
179
  return (
182
180
  <TabBar
183
181
  state={state}
184
182
  descriptors={descriptors}
185
- navigation={{ emit: () => ({}), navigate: () => {} }}
186
- backgroundColor="#1a1a1a"
187
- labelPosition="below-icon"
183
+ navigation={navigation}
184
+ activateOnFocus={false}
185
+ aria-label="Settings sections"
188
186
  />
189
187
  );
190
188
  }
191
189
  ```
192
190
 
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
191
  ## Accessibility
245
192
 
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
193
+ - Container is `<nav role="tablist" aria-orientation="horizontal">`; each tab is `role="tab"` with `aria-selected`.
194
+ - Roving tab index: only the active tab is in the tab order.
195
+ - Keyboard: `ArrowRight`/`ArrowDown` next, `ArrowLeft`/`ArrowUp` previous (both wrap), `Home`/`End` jump to ends, `Enter`/`Space` activates.
196
+ - The animated selection indicator is `aria-hidden` (web only).
197
+ - Provide `aria-label` or `aria-labelledby` so screen readers can name the tablist.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xsolla/xui-tab-bar",
3
- "version": "0.149.1",
3
+ "version": "0.151.0",
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.149.1",
17
- "@xsolla/xui-core": "0.149.1",
18
- "@xsolla/xui-primitives-core": "0.149.1"
16
+ "@xsolla/xui-badge": "0.151.0",
17
+ "@xsolla/xui-core": "0.151.0",
18
+ "@xsolla/xui-primitives-core": "0.151.0"
19
19
  },
20
20
  "peerDependencies": {
21
21
  "react": ">=16.8.0"