@hero-design/rn 7.1.3-alpha5 → 7.1.3-alpha8

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 (165) hide show
  1. package/.eslintrc.json +0 -6
  2. package/.expo/packager-info.json +1 -1
  3. package/babel.config.js +0 -14
  4. package/es/index.js +2787 -8941
  5. package/jest-setup.ts +0 -1
  6. package/jest.config.js +2 -4
  7. package/lib/index.js +2822 -8956
  8. package/package.json +5 -7
  9. package/playground/components/BottomNavigation.tsx +14 -11
  10. package/playground/components/Button.tsx +67 -0
  11. package/playground/components/Card.tsx +141 -107
  12. package/playground/components/Tabs.tsx +44 -0
  13. package/playground/index.tsx +13 -7
  14. package/src/components/Badge/StyledBadge.tsx +19 -21
  15. package/src/components/Badge/__tests__/Badge.spec.tsx +9 -18
  16. package/src/components/Badge/__tests__/__snapshots__/Badge.spec.tsx.snap +76 -96
  17. package/src/components/Badge/index.tsx +1 -1
  18. package/src/components/BottomNavigation/StyledBottomNavigation.tsx +44 -42
  19. package/src/components/BottomNavigation/__tests__/__snapshots__/{BottomNavigation.spec.tsx.snap → index.spec.tsx.snap} +130 -96
  20. package/src/components/BottomNavigation/__tests__/{BottomNavigation.spec.tsx → index.spec.tsx} +4 -4
  21. package/src/components/BottomNavigation/index.tsx +28 -32
  22. package/src/components/Button/IconButton.tsx +62 -0
  23. package/src/components/Button/__tests__/__snapshots__/index.spec.tsx.snap +46 -0
  24. package/src/components/Button/__tests__/index.spec.tsx +23 -0
  25. package/src/components/Button/index.tsx +5 -0
  26. package/src/components/Card/StyledCard.tsx +6 -6
  27. package/src/components/Card/__tests__/StyledCard.spec.tsx +2 -7
  28. package/src/components/Card/__tests__/__snapshots__/StyledCard.spec.tsx.snap +8 -11
  29. package/src/components/Card/__tests__/__snapshots__/{Card.spec.tsx.snap → index.spec.tsx.snap} +2 -8
  30. package/src/components/Card/__tests__/index.spec.tsx +35 -0
  31. package/src/components/Divider/StyledDivider.tsx +18 -60
  32. package/src/components/Divider/__tests__/StyledDivider.spec.tsx +5 -10
  33. package/src/components/Divider/__tests__/__snapshots__/StyledDivider.spec.tsx.snap +106 -70
  34. package/src/components/Divider/index.tsx +1 -1
  35. package/src/components/FAB/ActionGroup/ActionItem.tsx +2 -4
  36. package/src/components/FAB/ActionGroup/StyledActionGroup.tsx +36 -37
  37. package/src/components/FAB/ActionGroup/StyledActionItem.tsx +26 -24
  38. package/src/components/FAB/ActionGroup/__tests__/__snapshots__/index.spec.tsx.snap +271 -245
  39. package/src/components/FAB/ActionGroup/__tests__/index.spec.tsx +29 -33
  40. package/src/components/FAB/ActionGroup/index.tsx +1 -5
  41. package/src/components/FAB/AnimatedFABIcon.tsx +1 -1
  42. package/src/components/FAB/FAB.tsx +5 -9
  43. package/src/components/FAB/StyledFAB.tsx +22 -0
  44. package/src/components/FAB/__tests__/AnimatedFABIcon.spec.tsx +3 -6
  45. package/src/components/FAB/__tests__/StyledFAB.spec.tsx +24 -0
  46. package/src/components/FAB/__tests__/__snapshots__/AnimatedFABIcon.spec.tsx.snap +14 -10
  47. package/src/components/FAB/__tests__/__snapshots__/StyledFAB.spec.tsx.snap +72 -0
  48. package/src/components/FAB/__tests__/__snapshots__/index.spec.tsx.snap +16 -17
  49. package/src/components/FAB/__tests__/index.spec.tsx +21 -26
  50. package/src/components/Icon/HeroIcon/index.tsx +5 -7
  51. package/src/components/Icon/__tests__/__snapshots__/{Icon.spec.tsx.snap → index.spec.tsx.snap} +21 -12
  52. package/src/components/Icon/__tests__/index.spec.tsx +25 -0
  53. package/src/components/Icon/index.tsx +1 -1
  54. package/src/components/Tabs/StyledTabs.tsx +70 -0
  55. package/src/components/Tabs/__tests__/__snapshots__/index.spec.tsx.snap +321 -0
  56. package/src/components/Tabs/__tests__/index.spec.tsx +79 -0
  57. package/src/components/Tabs/index.tsx +185 -0
  58. package/src/components/Typography/Text/StyledText.tsx +19 -64
  59. package/src/components/Typography/Text/__tests__/__snapshots__/StyledText.spec.tsx.snap +90 -63
  60. package/src/emotion.d.ts +6 -0
  61. package/src/index.ts +9 -3
  62. package/src/testHelpers/renderWithTheme.tsx +2 -1
  63. package/src/theme/__tests__/__snapshots__/index.spec.ts.snap +70 -48
  64. package/src/theme/components/badge.ts +10 -9
  65. package/src/theme/components/bottomNavigation.ts +7 -3
  66. package/src/theme/components/card.ts +2 -2
  67. package/src/theme/components/divider.ts +6 -6
  68. package/src/theme/components/fab.ts +19 -17
  69. package/src/theme/components/tabs.ts +20 -0
  70. package/src/theme/components/typography.ts +4 -4
  71. package/src/theme/global/borders.ts +8 -2
  72. package/src/theme/global/colors.ts +3 -1
  73. package/src/theme/global/index.ts +31 -17
  74. package/src/theme/global/scale.ts +18 -0
  75. package/src/theme/global/space.ts +23 -13
  76. package/src/theme/global/typography.ts +71 -27
  77. package/src/theme/index.ts +29 -13
  78. package/src/types.ts +7 -0
  79. package/src/utils/__tests__/scale.spec.ts +3 -3
  80. package/testUtils/setup.ts +11 -0
  81. package/tsconfig.json +1 -5
  82. package/types/playground/components/BottomNavigation.d.ts +2 -2
  83. package/types/playground/components/Button.d.ts +2 -0
  84. package/types/playground/components/Tabs.d.ts +2 -0
  85. package/types/src/components/Badge/StyledBadge.d.ts +16 -5
  86. package/types/src/components/Badge/index.d.ts +1 -1
  87. package/types/src/components/BottomNavigation/StyledBottomNavigation.d.ts +44 -9
  88. package/types/src/components/{Typography/Text/__test__ → BottomNavigation/__tests__}/index.spec.d.ts +0 -0
  89. package/types/src/components/BottomNavigation/index.d.ts +19 -14
  90. package/types/src/components/Button/IconButton.d.ts +34 -0
  91. package/types/{theme → src/components/Button}/__tests__/index.spec.d.ts +0 -0
  92. package/types/src/components/Button/index.d.ts +4 -0
  93. package/types/src/components/Card/StyledCard.d.ts +7 -1
  94. package/types/{components/Card/__tests__/Card.spec.d.ts → src/components/Card/__tests__/index.spec.d.ts} +0 -0
  95. package/types/src/components/Divider/StyledDivider.d.ts +8 -2
  96. package/types/src/components/Divider/index.d.ts +1 -1
  97. package/types/src/components/FAB/ActionGroup/StyledActionGroup.d.ts +25 -7
  98. package/types/src/components/FAB/ActionGroup/StyledActionItem.d.ts +11 -2
  99. package/types/src/components/FAB/ActionGroup/index.d.ts +1 -1
  100. package/types/src/components/FAB/FAB.d.ts +4 -4
  101. package/types/src/components/FAB/StyledFAB.d.ts +14 -0
  102. package/types/{components/Card/__tests__/StyledCard.spec.d.ts → src/components/FAB/__tests__/StyledFAB.spec.d.ts} +0 -0
  103. package/types/src/components/Icon/HeroIcon/index.d.ts +8 -2
  104. package/types/{components/Divider/__tests__/StyledDivider.spec.d.ts → src/components/Icon/__tests__/index.spec.d.ts} +0 -0
  105. package/types/src/components/Icon/index.d.ts +1 -1
  106. package/types/src/components/Icon/utils.d.ts +1 -1
  107. package/types/src/components/Tabs/StyledTabs.d.ts +55 -0
  108. package/types/{components/ExampleComponent/__tests__/StyledView.spec.d.ts → src/components/Tabs/__tests__/index.spec.d.ts} +0 -0
  109. package/types/src/components/Tabs/index.d.ts +45 -0
  110. package/types/src/components/Typography/Text/StyledText.d.ts +8 -2
  111. package/types/src/index.d.ts +6 -3
  112. package/types/src/theme/components/badge.d.ts +8 -7
  113. package/types/src/theme/components/bottomNavigation.d.ts +8 -2
  114. package/types/src/theme/components/card.d.ts +2 -2
  115. package/types/src/theme/components/divider.d.ts +6 -6
  116. package/types/src/theme/components/fab.d.ts +19 -17
  117. package/types/src/theme/components/tabs.d.ts +15 -0
  118. package/types/src/theme/components/typography.d.ts +4 -4
  119. package/types/src/theme/global/borders.d.ts +4 -3
  120. package/types/src/theme/global/colors.d.ts +2 -2
  121. package/types/src/theme/global/index.d.ts +10 -45
  122. package/types/src/theme/global/scale.d.ts +8 -0
  123. package/types/src/theme/global/space.d.ts +8 -7
  124. package/types/src/theme/global/typography.d.ts +9 -16
  125. package/types/src/theme/index.d.ts +4 -2
  126. package/types/src/types.d.ts +5 -0
  127. package/lib/assets/fonts/be-vietnam-pro-light.ttf +0 -0
  128. package/lib/assets/fonts/be-vietnam-pro-regular.ttf +0 -0
  129. package/lib/assets/fonts/be-vietnam-pro-semibold.ttf +0 -0
  130. package/src/components/Card/__tests__/Card.spec.tsx +0 -36
  131. package/src/components/FAB/StyledFABContainer.tsx +0 -14
  132. package/src/components/FAB/StyledFABIcon.tsx +0 -9
  133. package/src/components/FAB/__tests__/StyledFABContainer.spec.tsx +0 -18
  134. package/src/components/FAB/__tests__/StyledFABIcon.spec.tsx +0 -16
  135. package/src/components/FAB/__tests__/__snapshots__/StyledFABContainer.spec.tsx.snap +0 -46
  136. package/src/components/FAB/__tests__/__snapshots__/StyledFABIcon.spec.tsx.snap +0 -21
  137. package/src/components/Icon/__tests__/Icon.spec.tsx +0 -36
  138. package/src/styled-components.ts +0 -14
  139. package/src/styled.d.ts +0 -7
  140. package/types/components/Card/StyledCard.d.ts +0 -3
  141. package/types/components/Card/index.d.ts +0 -5
  142. package/types/components/Divider/StyledDivider.d.ts +0 -7
  143. package/types/components/Divider/index.d.ts +0 -12
  144. package/types/components/ExampleComponent/StyledView.d.ts +0 -7
  145. package/types/components/ExampleComponent/index.d.ts +0 -16
  146. package/types/index.d.ts +0 -5
  147. package/types/src/components/BottomNavigation/__tests__/BottomNavigation.spec.d.ts +0 -1
  148. package/types/src/components/Card/__tests__/Card.spec.d.ts +0 -1
  149. package/types/src/components/FAB/StyledFABContainer.d.ts +0 -3
  150. package/types/src/components/FAB/StyledFABIcon.d.ts +0 -3
  151. package/types/src/components/FAB/__tests__/StyledFABContainer.spec.d.ts +0 -1
  152. package/types/src/components/FAB/__tests__/StyledFABIcon.spec.d.ts +0 -1
  153. package/types/src/components/Icon/__tests__/Icon.spec.d.ts +0 -1
  154. package/types/src/components/Typography/Text/__test__/StyledText.spec.d.ts +0 -1
  155. package/types/src/styled-components.d.ts +0 -6
  156. package/types/styled-components.d.ts +0 -6
  157. package/types/theme/components/card.d.ts +0 -10
  158. package/types/theme/components/divider.d.ts +0 -17
  159. package/types/theme/components/exampleComponent.d.ts +0 -14
  160. package/types/theme/global/borders.d.ts +0 -4
  161. package/types/theme/global/colors.d.ts +0 -26
  162. package/types/theme/global/index.d.ts +0 -63
  163. package/types/theme/global/space.d.ts +0 -12
  164. package/types/theme/global/typography.d.ts +0 -21
  165. package/types/theme/index.d.ts +0 -13
@@ -0,0 +1,321 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Tabs renders correctly 1`] = `
4
+ <RNCSafeAreaProvider
5
+ onInsetsChange={[Function]}
6
+ style={
7
+ Array [
8
+ Object {
9
+ "flex": 1,
10
+ },
11
+ undefined,
12
+ ]
13
+ }
14
+ >
15
+ <View
16
+ style={
17
+ Array [
18
+ Object {
19
+ "flex": 1,
20
+ "overflow": "hidden",
21
+ },
22
+ undefined,
23
+ ]
24
+ }
25
+ >
26
+ <View
27
+ style={
28
+ Array [
29
+ Object {
30
+ "backgroundColor": "#7622d7",
31
+ "paddingLeft": 0,
32
+ "paddingRight": 0,
33
+ },
34
+ undefined,
35
+ ]
36
+ }
37
+ themeInsets={
38
+ Object {
39
+ "bottom": 0,
40
+ "left": 0,
41
+ "right": 0,
42
+ "top": 0,
43
+ }
44
+ }
45
+ >
46
+ <RCTScrollView
47
+ data={
48
+ Array [
49
+ Object {
50
+ "component": <Text>
51
+ Work Screen
52
+ </Text>,
53
+ "icon": "suitcase",
54
+ "key": "work",
55
+ "title": "Work",
56
+ },
57
+ Object {
58
+ "component": <Text>
59
+ Personal Screen
60
+ </Text>,
61
+ "icon": "face-smiley",
62
+ "key": "personal",
63
+ "title": "Personal",
64
+ },
65
+ ]
66
+ }
67
+ getItem={[Function]}
68
+ getItemCount={[Function]}
69
+ horizontal={true}
70
+ keyExtractor={[Function]}
71
+ onContentSizeChange={[Function]}
72
+ onLayout={[Function]}
73
+ onMomentumScrollBegin={[Function]}
74
+ onMomentumScrollEnd={[Function]}
75
+ onScroll={[Function]}
76
+ onScrollBeginDrag={[Function]}
77
+ onScrollEndDrag={[Function]}
78
+ onScrollToIndexFailed={[Function]}
79
+ removeClippedSubviews={false}
80
+ renderItem={[Function]}
81
+ scrollEventThrottle={50}
82
+ showsHorizontalScrollIndicator={false}
83
+ stickyHeaderIndices={Array []}
84
+ style={
85
+ Array [
86
+ Object {
87
+ "paddingLeft": 8,
88
+ "paddingRight": 8,
89
+ },
90
+ undefined,
91
+ ]
92
+ }
93
+ viewabilityConfigCallbackPairs={Array []}
94
+ >
95
+ <View>
96
+ <View
97
+ onLayout={[Function]}
98
+ style={
99
+ Array [
100
+ Object {
101
+ "flexDirection": "row",
102
+ },
103
+ null,
104
+ ]
105
+ }
106
+ >
107
+ <View
108
+ accessible={true}
109
+ collapsable={false}
110
+ focusable={true}
111
+ nativeID="animatedComponent"
112
+ onClick={[Function]}
113
+ onResponderGrant={[Function]}
114
+ onResponderMove={[Function]}
115
+ onResponderRelease={[Function]}
116
+ onResponderTerminate={[Function]}
117
+ onResponderTerminationRequest={[Function]}
118
+ onStartShouldSetResponder={[Function]}
119
+ style={
120
+ Object {
121
+ "opacity": 1,
122
+ }
123
+ }
124
+ >
125
+ <View
126
+ style={
127
+ Array [
128
+ Object {
129
+ "alignItems": "center",
130
+ "flexDirection": "row",
131
+ "paddingBottom": 24,
132
+ "paddingLeft": 16,
133
+ "paddingRight": 16,
134
+ "paddingTop": 24,
135
+ },
136
+ undefined,
137
+ ]
138
+ }
139
+ >
140
+ <HeroIcon
141
+ name="suitcase"
142
+ style={
143
+ Array [
144
+ Object {
145
+ "color": "#292a2b",
146
+ "fontSize": 24,
147
+ },
148
+ Array [
149
+ Object {
150
+ "color": "#ffffff",
151
+ },
152
+ undefined,
153
+ ],
154
+ ]
155
+ }
156
+ testID="hero-icon-suitcase"
157
+ themeIntent="text"
158
+ themeSize="medium"
159
+ />
160
+ <Text
161
+ numberOfLines={1}
162
+ style={
163
+ Array [
164
+ Object {
165
+ "color": "#292a2b",
166
+ "fontFamily": "BeVietnamPro-SemiBold",
167
+ "fontSize": 14,
168
+ "letterSpacing": 0.42,
169
+ "lineHeight": 22,
170
+ },
171
+ Array [
172
+ Object {
173
+ "color": "#ffffff",
174
+ "marginLeft": 8,
175
+ },
176
+ undefined,
177
+ ],
178
+ ]
179
+ }
180
+ themeActive={true}
181
+ themeFontSize="medium"
182
+ themeFontWeight="semi-bold"
183
+ themeIntent="body"
184
+ >
185
+ Work
186
+ </Text>
187
+ </View>
188
+ </View>
189
+ </View>
190
+ <View
191
+ onLayout={[Function]}
192
+ style={
193
+ Array [
194
+ Object {
195
+ "flexDirection": "row",
196
+ },
197
+ null,
198
+ ]
199
+ }
200
+ >
201
+ <View
202
+ accessible={true}
203
+ collapsable={false}
204
+ focusable={true}
205
+ nativeID="animatedComponent"
206
+ onClick={[Function]}
207
+ onResponderGrant={[Function]}
208
+ onResponderMove={[Function]}
209
+ onResponderRelease={[Function]}
210
+ onResponderTerminate={[Function]}
211
+ onResponderTerminationRequest={[Function]}
212
+ onStartShouldSetResponder={[Function]}
213
+ style={
214
+ Object {
215
+ "opacity": 1,
216
+ }
217
+ }
218
+ >
219
+ <View
220
+ style={
221
+ Array [
222
+ Object {
223
+ "alignItems": "center",
224
+ "flexDirection": "row",
225
+ "paddingBottom": 24,
226
+ "paddingLeft": 16,
227
+ "paddingRight": 16,
228
+ "paddingTop": 24,
229
+ },
230
+ undefined,
231
+ ]
232
+ }
233
+ >
234
+ <HeroIcon
235
+ name="face-smiley"
236
+ style={
237
+ Array [
238
+ Object {
239
+ "color": "#292a2b",
240
+ "fontSize": 24,
241
+ },
242
+ Array [
243
+ Object {
244
+ "color": "#ffffff50",
245
+ },
246
+ undefined,
247
+ ],
248
+ ]
249
+ }
250
+ testID="hero-icon-face-smiley"
251
+ themeIntent="text"
252
+ themeSize="medium"
253
+ />
254
+ <Text
255
+ numberOfLines={1}
256
+ style={
257
+ Array [
258
+ Object {
259
+ "color": "#292a2b",
260
+ "fontFamily": "BeVietnamPro-SemiBold",
261
+ "fontSize": 14,
262
+ "letterSpacing": 0.42,
263
+ "lineHeight": 22,
264
+ },
265
+ Array [
266
+ Object {
267
+ "color": "#ffffff50",
268
+ "marginLeft": 8,
269
+ },
270
+ undefined,
271
+ ],
272
+ ]
273
+ }
274
+ themeActive={false}
275
+ themeFontSize="medium"
276
+ themeFontWeight="semi-bold"
277
+ themeIntent="body"
278
+ >
279
+ Personal
280
+ </Text>
281
+ </View>
282
+ </View>
283
+ </View>
284
+ </View>
285
+ </RCTScrollView>
286
+ </View>
287
+ <View
288
+ style={
289
+ Array [
290
+ Object {
291
+ "flex": 1,
292
+ },
293
+ undefined,
294
+ ]
295
+ }
296
+ >
297
+ <View
298
+ accessibilityElementsHidden={false}
299
+ collapsable={false}
300
+ importantForAccessibility="auto"
301
+ pointerEvents="auto"
302
+ removeClippedSubviews={false}
303
+ style={
304
+ Array [
305
+ Object {
306
+ "display": "flex",
307
+ "flex": 1,
308
+ },
309
+ undefined,
310
+ ]
311
+ }
312
+ themeVisibility={true}
313
+ >
314
+ <Text>
315
+ Work Screen
316
+ </Text>
317
+ </View>
318
+ </View>
319
+ </View>
320
+ </RNCSafeAreaProvider>
321
+ `;
@@ -0,0 +1,79 @@
1
+ import React, { ComponentProps } from 'react';
2
+ import { Text } from 'react-native';
3
+ import { fireEvent } from '@testing-library/react-native';
4
+ import { SafeAreaProvider } from 'react-native-safe-area-context';
5
+ import renderWithTheme from '../../../testHelpers/renderWithTheme';
6
+ import Tabs, { TabType } from '..';
7
+
8
+ const TestTabsComponent = (
9
+ props: Omit<
10
+ ComponentProps<typeof Tabs>,
11
+ 'selectedTabKey' | 'onTabPress' | 'tabs'
12
+ >
13
+ ) => {
14
+ const [selectedTabKey, setSelectedTabKey] = React.useState('work');
15
+ const tabs: TabType[] = [
16
+ {
17
+ key: 'work',
18
+ title: 'Work',
19
+ icon: 'suitcase',
20
+ component: <Text>Work Screen</Text>,
21
+ },
22
+ {
23
+ key: 'personal',
24
+ title: 'Personal',
25
+ icon: 'face-smiley',
26
+ component: <Text>Personal Screen</Text>,
27
+ },
28
+ ];
29
+
30
+ return (
31
+ <SafeAreaProvider
32
+ initialMetrics={{
33
+ frame: { x: 0, y: 0, width: 0, height: 0 },
34
+ insets: { top: 0, left: 0, right: 0, bottom: 0 },
35
+ }}
36
+ >
37
+ <Tabs
38
+ {...props}
39
+ tabs={tabs}
40
+ selectedTabKey={selectedTabKey}
41
+ onTabPress={newTabKey => setSelectedTabKey(newTabKey)}
42
+ />
43
+ </SafeAreaProvider>
44
+ );
45
+ };
46
+
47
+ describe('Tabs', () => {
48
+ it('renders correctly', () => {
49
+ const { getByTestId, getByText, toJSON } = renderWithTheme(
50
+ <TestTabsComponent />
51
+ );
52
+
53
+ expect(toJSON()).toMatchSnapshot();
54
+ expect(getByText('Work')).toBeDefined();
55
+ expect(getByText('Personal')).toBeDefined();
56
+ expect(getByTestId('hero-icon-suitcase')).toBeDefined();
57
+ expect(getByTestId('hero-icon-face-smiley')).toBeDefined();
58
+ fireEvent.press(getByText('Personal'));
59
+
60
+ // All screens are rendered and component is not unmounted when switching screen.
61
+ expect(getByText('Work Screen')).toBeDefined();
62
+ expect(getByText('Personal Screen')).toBeDefined();
63
+ });
64
+
65
+ it('renders correctly with renderActiveTabOnly is true', () => {
66
+ const { getByText, queryByText, getByTestId } = renderWithTheme(
67
+ <TestTabsComponent renderActiveTabOnly />
68
+ );
69
+
70
+ // Can switch tab by clicking icon.
71
+ fireEvent.press(getByTestId('hero-icon-face-smiley'));
72
+ expect(getByText('Personal Screen')).toBeDefined();
73
+ fireEvent.press(getByTestId('hero-icon-suitcase'));
74
+ expect(getByText('Work Screen')).toBeDefined();
75
+
76
+ // Only render selected screen, others are unmounted.
77
+ expect(queryByText('Personal Screen')).toBeNull();
78
+ });
79
+ });
@@ -0,0 +1,185 @@
1
+ import React, { ReactNode } from 'react';
2
+ import {
3
+ TouchableOpacity,
4
+ StyleProp,
5
+ ViewStyle,
6
+ ViewProps,
7
+ FlatList,
8
+ } from 'react-native';
9
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
10
+ import {
11
+ HeaderTabItem,
12
+ HeaderTabWrapper,
13
+ StyledHeaderTabText,
14
+ StyledHeaderTabIcon,
15
+ TabContainer,
16
+ TabScreen,
17
+ ContentWrapper,
18
+ StyledFlatList,
19
+ } from './StyledTabs';
20
+ import { isIOS } from '../../utils/helpers';
21
+ import { IconName } from '../Icon';
22
+
23
+ export type TabType = {
24
+ key: string;
25
+ title: string;
26
+ icon: IconName;
27
+ component: ReactNode;
28
+ testID?: string;
29
+ };
30
+
31
+ interface TabsProps extends ViewProps {
32
+ /**
33
+ * Callback which is called on tab press, receiving key of upcoming active Tab.
34
+ */
35
+ onTabPress: (key: string) => void;
36
+ /**
37
+ * Whether inactive tabs should be removed and unmounted in React.
38
+ * Defaults to `false`.
39
+ */
40
+ renderActiveTabOnly?: boolean;
41
+ /**
42
+ * Current selected tab key.
43
+ */
44
+ selectedTabKey: string;
45
+ /**
46
+ * List of Tabs to be rendered. Each Tab must have an unique key.
47
+ */
48
+ tabs: {
49
+ key: string;
50
+ title: string;
51
+ icon: IconName;
52
+ component: ReactNode;
53
+ testID?: string;
54
+ }[];
55
+ /**
56
+ * Addditional style.
57
+ */
58
+ style?: StyleProp<ViewStyle>;
59
+ /**
60
+ * Testing id of the component.
61
+ */
62
+ testID?: string;
63
+ }
64
+
65
+ const Tabs = ({
66
+ onTabPress,
67
+ renderActiveTabOnly = false,
68
+ selectedTabKey,
69
+ tabs,
70
+ ...nativeProps
71
+ }: TabsProps): JSX.Element => {
72
+ const flatListRef = React.useRef<FlatList>(null);
73
+ const insets = useSafeAreaInsets();
74
+
75
+ /**
76
+ * List of loaded tabs, tabs will be loaded when navigated to.
77
+ */
78
+ const [loaded, setLoaded] = React.useState([selectedTabKey]);
79
+
80
+ React.useEffect(() => {
81
+ const selectedTabIndex = tabs.findIndex(
82
+ item => item.key === selectedTabKey
83
+ );
84
+ if (selectedTabIndex !== -1) {
85
+ flatListRef.current?.scrollToIndex({
86
+ index: selectedTabIndex,
87
+ viewPosition: 0.5,
88
+ });
89
+ }
90
+ }, [selectedTabKey, tabs]);
91
+
92
+ if (!loaded.includes(selectedTabKey)) {
93
+ // Set the current tab to be loaded if it was not loaded before
94
+ setLoaded(loadedState => [...loadedState, selectedTabKey]);
95
+ }
96
+
97
+ return (
98
+ <TabContainer {...nativeProps}>
99
+ <HeaderTabWrapper themeInsets={insets}>
100
+ <StyledFlatList<TabType>
101
+ ref={flatListRef}
102
+ horizontal
103
+ data={tabs}
104
+ keyExtractor={tab => String(tab.key)}
105
+ showsHorizontalScrollIndicator={false}
106
+ onScrollToIndexFailed={({ index }) => {
107
+ setTimeout(
108
+ () =>
109
+ flatListRef.current?.scrollToIndex({
110
+ index,
111
+ viewPosition: 0.5,
112
+ }),
113
+ 100
114
+ );
115
+ }}
116
+ renderItem={({ item: tab }) => {
117
+ const { key, icon, title, testID } = tab;
118
+ const active = selectedTabKey === key;
119
+
120
+ return (
121
+ <TouchableOpacity
122
+ key={key}
123
+ onPress={() => onTabPress(key)}
124
+ testID={testID}
125
+ >
126
+ <HeaderTabItem>
127
+ <StyledHeaderTabIcon
128
+ icon={icon}
129
+ testID={`hero-icon-${icon}`}
130
+ themeActive={active}
131
+ />
132
+ <StyledHeaderTabText
133
+ fontWeight="semi-bold"
134
+ numberOfLines={1}
135
+ themeActive={active}
136
+ >
137
+ {title}
138
+ </StyledHeaderTabText>
139
+ </HeaderTabItem>
140
+ </TouchableOpacity>
141
+ );
142
+ }}
143
+ />
144
+ </HeaderTabWrapper>
145
+ <ContentWrapper>
146
+ {tabs.map(tab => {
147
+ const { key, component, testID } = tab;
148
+ const active = selectedTabKey === key;
149
+
150
+ if (renderActiveTabOnly && !active) {
151
+ return null;
152
+ }
153
+
154
+ if (!loaded.includes(key)) {
155
+ // Don't render a screen if we've never navigated to it
156
+ return null;
157
+ }
158
+
159
+ return (
160
+ <TabScreen
161
+ key={key}
162
+ testID={testID ? `tab-screen-${testID}` : undefined}
163
+ pointerEvents={active ? 'auto' : 'none'}
164
+ accessibilityElementsHidden={!active}
165
+ importantForAccessibility={
166
+ active ? 'auto' : 'no-hide-descendants'
167
+ }
168
+ collapsable={false}
169
+ removeClippedSubviews={
170
+ // On iOS, set removeClippedSubviews to true only when not focused
171
+ // This is an workaround for a bug where the clipped view never re-appears.
172
+ isIOS ? selectedTabKey !== key : true
173
+ }
174
+ themeVisibility={active}
175
+ >
176
+ {component}
177
+ </TabScreen>
178
+ );
179
+ })}
180
+ </ContentWrapper>
181
+ </TabContainer>
182
+ );
183
+ };
184
+
185
+ export default Tabs;
@@ -1,73 +1,28 @@
1
1
  import { Text } from 'react-native';
2
- import styled, { css } from '../../../styled-components';
2
+ import styled from '@emotion/native';
3
+
4
+ const FONTWEIGHT_MAP = {
5
+ light: 'light',
6
+ regular: 'regular',
7
+ 'semi-bold': 'semiBold',
8
+ } as const;
3
9
 
4
10
  const StyledText = styled(Text)<{
5
11
  themeFontSize: 'small' | 'medium' | 'large' | 'xlarge';
6
12
  themeFontWeight: 'light' | 'regular' | 'semi-bold';
7
13
  themeIntent: 'body' | 'subdued' | 'primary';
8
- }>`
9
- ${({ themeFontSize, theme }) => {
10
- switch (themeFontSize) {
11
- case 'small':
12
- return css`
13
- font-size: ${theme.__hd__.typography.fontSizes.small}px;
14
- line-height: ${theme.__hd__.typography.lineHeights.small};
15
- letter-spacing: ${theme.__hd__.typography.fontSizes.small * 0.03}px;
16
- `;
17
- case 'medium':
18
- return css`
19
- font-size: ${theme.__hd__.typography.fontSizes.medium}px;
20
- line-height: ${theme.__hd__.typography.lineHeights.medium};
21
- letter-spacing: ${theme.__hd__.typography.fontSizes.medium * 0.03}px;
22
- `;
23
- case 'large':
24
- return css`
25
- font-size: ${theme.__hd__.typography.fontSizes.large}px;
26
- line-height: ${theme.__hd__.typography.lineHeights.large};
27
- letter-spacing: ${theme.__hd__.typography.fontSizes.large * 0.03}px;
28
- `;
29
- case 'xlarge':
30
- return css`
31
- font-size: ${theme.__hd__.typography.fontSizes.xlarge}px;
32
- line-height: ${theme.__hd__.typography.lineHeights.xlarge};
33
- letter-spacing: ${theme.__hd__.typography.fontSizes.xlarge * 0.03}px;
34
- `;
35
- }
36
- }}
37
-
38
- ${({ themeFontWeight, theme }) => {
39
- switch (themeFontWeight) {
40
- case 'light':
41
- return css`
42
- font-family: ${theme.__hd__.typography.fonts.light};
43
- `;
44
- case 'regular':
45
- return css`
46
- font-family: ${theme.__hd__.typography.fonts.regular};
47
- `;
48
- case 'semi-bold':
49
- return css`
50
- font-family: ${theme.__hd__.typography.fonts.semiBold};
51
- `;
52
- }
53
- }}
14
+ }>(({ themeFontSize, themeFontWeight, themeIntent, theme }) => {
15
+ const sizeStyles = {
16
+ fontSize: theme.__hd__.typography.fontSizes[themeFontSize],
17
+ lineHeight: theme.__hd__.typography.lineHeights[themeFontSize],
18
+ letterSpacing: theme.__hd__.typography.fontSizes[themeFontSize] * 0.03,
19
+ };
54
20
 
55
- ${({ themeIntent, theme }) => {
56
- switch (themeIntent) {
57
- case 'body':
58
- return css`
59
- color: ${theme.__hd__.typography.colors.body};
60
- `;
61
- case 'subdued':
62
- return css`
63
- color: ${theme.__hd__.typography.colors.subdued};
64
- `;
65
- case 'primary':
66
- return css`
67
- color: ${theme.__hd__.typography.colors.primary};
68
- `;
69
- }
70
- }}
71
- `;
21
+ return {
22
+ ...sizeStyles,
23
+ fontFamily: theme.__hd__.typography.fonts[FONTWEIGHT_MAP[themeFontWeight]],
24
+ color: theme.__hd__.typography.colors[themeIntent],
25
+ };
26
+ });
72
27
 
73
28
  export { StyledText };