@hero-design/rn 7.0.6 → 7.1.2

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 (92) hide show
  1. package/.eslintrc.json +4 -3
  2. package/babel.config.js +1 -1
  3. package/es/index.js +411 -134
  4. package/lib/index.js +411 -131
  5. package/package.json +5 -4
  6. package/playground/components/BottomNavigation.tsx +69 -0
  7. package/playground/components/Card.tsx +174 -112
  8. package/playground/components/FAB.tsx +49 -0
  9. package/playground/index.tsx +6 -1
  10. package/rollup.config.js +1 -1
  11. package/src/components/BottomNavigation/StyledBottomNavigation.tsx +58 -0
  12. package/src/components/BottomNavigation/__tests__/BottomNavigation.spec.tsx +95 -0
  13. package/src/components/BottomNavigation/__tests__/__snapshots__/BottomNavigation.spec.tsx.snap +315 -0
  14. package/src/components/BottomNavigation/index.tsx +169 -0
  15. package/src/components/Card/StyledCard.tsx +1 -0
  16. package/src/components/Card/__tests__/__snapshots__/Card.spec.tsx.snap +5 -4
  17. package/src/components/Card/__tests__/__snapshots__/StyledCard.spec.tsx.snap +5 -4
  18. package/src/components/FAB/AnimatedFABIcon.tsx +47 -0
  19. package/src/components/FAB/StyledFABContainer.tsx +14 -0
  20. package/src/components/FAB/StyledFABIcon.tsx +9 -0
  21. package/src/components/FAB/__tests__/AnimatedFABIcon.spec.tsx +20 -0
  22. package/src/components/FAB/__tests__/StyledFABContainer.spec.tsx +18 -0
  23. package/src/components/FAB/__tests__/StyledFABIcon.spec.tsx +16 -0
  24. package/src/components/FAB/__tests__/__snapshots__/AnimatedFABIcon.spec.tsx.snap +71 -0
  25. package/src/components/FAB/__tests__/__snapshots__/StyledFABContainer.spec.tsx.snap +46 -0
  26. package/src/components/FAB/__tests__/__snapshots__/StyledFABIcon.spec.tsx.snap +21 -0
  27. package/src/components/FAB/__tests__/__snapshots__/index.spec.tsx.snap +120 -0
  28. package/src/components/FAB/__tests__/index.spec.tsx +58 -0
  29. package/src/components/FAB/index.tsx +56 -0
  30. package/src/components/Icon/index.tsx +1 -1
  31. package/src/components/Icon/utils.ts +6 -0
  32. package/src/components/Typography/Text/StyledText.tsx +5 -1
  33. package/src/components/Typography/Text/index.tsx +1 -1
  34. package/src/index.ts +6 -0
  35. package/src/theme/__tests__/__snapshots__/index.spec.ts.snap +30 -1
  36. package/src/theme/components/bottomNavigation.ts +23 -0
  37. package/src/theme/components/card.ts +1 -1
  38. package/src/theme/components/fab.ts +21 -0
  39. package/src/theme/components/typography.ts +1 -0
  40. package/src/theme/global/space.ts +11 -9
  41. package/src/theme/global/typography.ts +11 -9
  42. package/src/theme/index.ts +6 -0
  43. package/src/utils/__tests__/scale.spec.ts +26 -0
  44. package/src/utils/helpers.ts +4 -0
  45. package/src/utils/scale.ts +10 -0
  46. package/testUtils/setup.ts +4 -0
  47. package/types/playground/components/BottomNavigation.d.ts +2 -0
  48. package/types/playground/components/FAB.d.ts +2 -0
  49. package/types/src/components/BottomNavigation/StyledBottomNavigation.d.ts +17 -0
  50. package/types/{components/Card/__tests__/Card.spec.d.ts → src/components/BottomNavigation/__tests__/BottomNavigation.spec.d.ts} +0 -0
  51. package/types/src/components/BottomNavigation/index.d.ts +40 -0
  52. package/types/src/components/FAB/AnimatedFABIcon.d.ts +6 -0
  53. package/types/src/components/FAB/StyledFABContainer.d.ts +3 -0
  54. package/types/src/components/FAB/StyledFABIcon.d.ts +3 -0
  55. package/types/{components/Card/__tests__/StyledCard.spec.d.ts → src/components/FAB/__tests__/AnimatedFABIcon.spec.d.ts} +0 -0
  56. package/types/{components/Divider/__tests__/StyledDivider.spec.d.ts → src/components/FAB/__tests__/StyledFABContainer.spec.d.ts} +0 -0
  57. package/types/{components/ExampleComponent/__tests__/StyledView.spec.d.ts → src/components/FAB/__tests__/StyledFABIcon.spec.d.ts} +0 -0
  58. package/types/src/components/{Typography/Text/__test__ → FAB/__tests__}/index.spec.d.ts +0 -0
  59. package/types/src/components/FAB/index.d.ts +30 -0
  60. package/types/src/components/Icon/index.d.ts +1 -1
  61. package/types/src/components/Icon/utils.d.ts +2 -0
  62. package/types/src/components/Typography/Text/StyledText.d.ts +1 -1
  63. package/types/src/components/Typography/Text/index.d.ts +1 -1
  64. package/types/src/index.d.ts +4 -1
  65. package/types/src/theme/components/bottomNavigation.d.ts +17 -0
  66. package/types/src/theme/components/fab.d.ts +15 -0
  67. package/types/src/theme/components/typography.d.ts +1 -0
  68. package/types/src/theme/index.d.ts +4 -0
  69. package/types/src/{components/Typography/Text/__test__/StyledText.spec.d.ts → utils/__tests__/scale.spec.d.ts} +0 -0
  70. package/types/src/utils/helpers.d.ts +2 -0
  71. package/types/src/utils/scale.d.ts +2 -0
  72. package/.expo/README.md +0 -15
  73. package/.expo/packager-info.json +0 -10
  74. package/.expo/settings.json +0 -10
  75. package/types/components/Card/StyledCard.d.ts +0 -3
  76. package/types/components/Card/index.d.ts +0 -5
  77. package/types/components/Divider/StyledDivider.d.ts +0 -7
  78. package/types/components/Divider/index.d.ts +0 -12
  79. package/types/components/ExampleComponent/StyledView.d.ts +0 -7
  80. package/types/components/ExampleComponent/index.d.ts +0 -16
  81. package/types/index.d.ts +0 -5
  82. package/types/styled-components.d.ts +0 -6
  83. package/types/theme/__tests__/index.spec.d.ts +0 -1
  84. package/types/theme/components/card.d.ts +0 -10
  85. package/types/theme/components/divider.d.ts +0 -17
  86. package/types/theme/components/exampleComponent.d.ts +0 -14
  87. package/types/theme/global/borders.d.ts +0 -4
  88. package/types/theme/global/colors.d.ts +0 -26
  89. package/types/theme/global/index.d.ts +0 -63
  90. package/types/theme/global/space.d.ts +0 -12
  91. package/types/theme/global/typography.d.ts +0 -21
  92. package/types/theme/index.d.ts +0 -13
@@ -0,0 +1,95 @@
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 BottomNavigation, { Tab } from '..';
7
+
8
+ const TestComponent = (
9
+ props: Omit<
10
+ ComponentProps<typeof BottomNavigation>,
11
+ 'selectedTabKey' | 'onChange' | 'tabs'
12
+ >
13
+ ) => {
14
+ const [selectedTabKey, setSelectedTabKey] = React.useState('home');
15
+ const tabs: Tab<string>[] = [
16
+ {
17
+ key: 'home',
18
+ title: 'Home',
19
+ icon: 'home',
20
+ component: <Text>Home Screen</Text>,
21
+ },
22
+ {
23
+ key: 'feed',
24
+ title: 'Feed',
25
+ icon: 'speaker-outlined',
26
+ component: <Text>Feed Screen</Text>,
27
+ },
28
+ {
29
+ key: 'alerts',
30
+ title: 'Alerts',
31
+ icon: 'bell-outlined',
32
+ component: <Text>Alerts Screen</Text>,
33
+ },
34
+ {
35
+ key: 'profile',
36
+ title: 'Profile',
37
+ icon: 'user-outlined',
38
+ component: <Text>Profile Screen</Text>,
39
+ },
40
+ ];
41
+
42
+ return (
43
+ <SafeAreaProvider
44
+ initialMetrics={{
45
+ frame: { x: 0, y: 0, width: 0, height: 0 },
46
+ insets: { top: 0, left: 0, right: 0, bottom: 0 },
47
+ }}
48
+ >
49
+ <BottomNavigation
50
+ {...props}
51
+ tabs={tabs}
52
+ selectedTabKey={selectedTabKey}
53
+ onChange={newTabKey => setSelectedTabKey(newTabKey)}
54
+ />
55
+ </SafeAreaProvider>
56
+ );
57
+ };
58
+
59
+ describe('BottomNavigation', () => {
60
+ it('renders correctly', () => {
61
+ const { getByText, toJSON } = renderWithTheme(<TestComponent />);
62
+
63
+ expect(toJSON()).toMatchSnapshot();
64
+ expect(getByText('Home')).toBeDefined();
65
+ fireEvent.press(getByText('Feed'));
66
+ fireEvent.press(getByText('Alerts'));
67
+ fireEvent.press(getByText('Profile'));
68
+
69
+ // All screens are rendered and component is not unmounted when switching screen.
70
+ expect(getByText('Home Screen')).toBeDefined();
71
+ expect(getByText('Feed Screen')).toBeDefined();
72
+ expect(getByText('Alerts Screen')).toBeDefined();
73
+ expect(getByText('Profile Screen')).toBeDefined();
74
+ });
75
+
76
+ it('renders correctly with renderActiveTabOnly is true', () => {
77
+ const { getByText, queryByText, getByTestId } = renderWithTheme(
78
+ <TestComponent renderActiveTabOnly />
79
+ );
80
+
81
+ // Can switch tab by clicking icon.
82
+ expect(getByText('Home Screen')).toBeDefined();
83
+ fireEvent.press(getByTestId('hero-icon-speaker-outlined'));
84
+ expect(getByText('Feed Screen')).toBeDefined();
85
+ fireEvent.press(getByTestId('hero-icon-bell-outlined'));
86
+ expect(getByText('Alerts Screen')).toBeDefined();
87
+ fireEvent.press(getByTestId('hero-icon-user-outlined'));
88
+ expect(getByText('Profile Screen')).toBeDefined();
89
+
90
+ // Only render selected screen, others are unmounted.
91
+ expect(queryByText('Home Screen')).toBeNull();
92
+ expect(queryByText('Feed Screen')).toBeNull();
93
+ expect(queryByText('Alerts Screen')).toBeNull();
94
+ });
95
+ });
@@ -0,0 +1,315 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`BottomNavigation 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
+ Object {
18
+ "flexBasis": 0,
19
+ "flexGrow": 1,
20
+ "flexShrink": 1,
21
+ "overflow": "hidden",
22
+ }
23
+ }
24
+ >
25
+ <View
26
+ style={
27
+ Object {
28
+ "flexBasis": 0,
29
+ "flexGrow": 1,
30
+ "flexShrink": 1,
31
+ }
32
+ }
33
+ >
34
+ <View
35
+ accessibilityElementsHidden={false}
36
+ collapsable={false}
37
+ importantForAccessibility="auto"
38
+ pointerEvents="auto"
39
+ removeClippedSubviews={false}
40
+ style={
41
+ Object {
42
+ "display": "flex",
43
+ "flexBasis": 0,
44
+ "flexGrow": 1,
45
+ "flexShrink": 1,
46
+ }
47
+ }
48
+ testID="route-screen-home"
49
+ themeVisibility={true}
50
+ >
51
+ <Text>
52
+ Home Screen
53
+ </Text>
54
+ </View>
55
+ </View>
56
+ <View
57
+ style={
58
+ Object {
59
+ "backgroundColor": "#ffffff",
60
+ "elevation": 10,
61
+ "height": 72,
62
+ "paddingBottom": 0,
63
+ "paddingLeft": 0,
64
+ "paddingRight": 0,
65
+ "shadowColor": "#292a2b",
66
+ "shadowOffset": Object {
67
+ "height": 3,
68
+ "width": 0,
69
+ },
70
+ "shadowOpacity": 0.27,
71
+ "shadowRadius": 4.65,
72
+ }
73
+ }
74
+ themeInsets={
75
+ Object {
76
+ "bottom": 0,
77
+ "left": 0,
78
+ "right": 0,
79
+ "top": 0,
80
+ }
81
+ }
82
+ >
83
+ <View
84
+ style={
85
+ Object {
86
+ "alignItems": "center",
87
+ "flexBasis": 0,
88
+ "flexDirection": "row",
89
+ "flexGrow": 1,
90
+ "flexShrink": 1,
91
+ "overflow": "hidden",
92
+ }
93
+ }
94
+ >
95
+ <View
96
+ accessible={true}
97
+ focusable={true}
98
+ onClick={[Function]}
99
+ onResponderGrant={[Function]}
100
+ onResponderMove={[Function]}
101
+ onResponderRelease={[Function]}
102
+ onResponderTerminate={[Function]}
103
+ onResponderTerminationRequest={[Function]}
104
+ onStartShouldSetResponder={[Function]}
105
+ style={
106
+ Object {
107
+ "alignItems": "center",
108
+ "flexBasis": 0,
109
+ "flexGrow": 1,
110
+ "flexShrink": 1,
111
+ }
112
+ }
113
+ >
114
+ <HeroIcon
115
+ name="home"
116
+ style={
117
+ Object {
118
+ "color": "#7622d7",
119
+ "fontSize": 24,
120
+ }
121
+ }
122
+ testID="hero-icon-home"
123
+ themeIntent="primary"
124
+ themeSize="medium"
125
+ />
126
+ <Text
127
+ numberOfLines={1}
128
+ style={
129
+ Array [
130
+ Object {
131
+ "color": "#7622d7",
132
+ "fontSize": 12,
133
+ "fontWeight": "600",
134
+ "letterSpacing": 0.36,
135
+ "lineHeight": 20,
136
+ },
137
+ Object {
138
+ "marginTop": 4,
139
+ },
140
+ ]
141
+ }
142
+ themeFontSize="small"
143
+ themeFontWeight="semi-bold"
144
+ themeIntent="primary"
145
+ >
146
+ Home
147
+ </Text>
148
+ </View>
149
+ <View
150
+ accessible={true}
151
+ focusable={true}
152
+ onClick={[Function]}
153
+ onResponderGrant={[Function]}
154
+ onResponderMove={[Function]}
155
+ onResponderRelease={[Function]}
156
+ onResponderTerminate={[Function]}
157
+ onResponderTerminationRequest={[Function]}
158
+ onStartShouldSetResponder={[Function]}
159
+ style={
160
+ Object {
161
+ "alignItems": "center",
162
+ "flexBasis": 0,
163
+ "flexGrow": 1,
164
+ "flexShrink": 1,
165
+ }
166
+ }
167
+ >
168
+ <HeroIcon
169
+ name="speaker-outlined"
170
+ style={
171
+ Object {
172
+ "color": "#292a2b",
173
+ "fontSize": 24,
174
+ }
175
+ }
176
+ testID="hero-icon-speaker-outlined"
177
+ themeIntent="text"
178
+ themeSize="medium"
179
+ />
180
+ <Text
181
+ numberOfLines={1}
182
+ style={
183
+ Array [
184
+ Object {
185
+ "color": "#292a2b",
186
+ "fontSize": 12,
187
+ "fontWeight": "600",
188
+ "letterSpacing": 0.36,
189
+ "lineHeight": 20,
190
+ },
191
+ Object {
192
+ "marginTop": 4,
193
+ },
194
+ ]
195
+ }
196
+ themeFontSize="small"
197
+ themeFontWeight="semi-bold"
198
+ themeIntent="body"
199
+ >
200
+ Feed
201
+ </Text>
202
+ </View>
203
+ <View
204
+ accessible={true}
205
+ focusable={true}
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
+ "alignItems": "center",
216
+ "flexBasis": 0,
217
+ "flexGrow": 1,
218
+ "flexShrink": 1,
219
+ }
220
+ }
221
+ >
222
+ <HeroIcon
223
+ name="bell-outlined"
224
+ style={
225
+ Object {
226
+ "color": "#292a2b",
227
+ "fontSize": 24,
228
+ }
229
+ }
230
+ testID="hero-icon-bell-outlined"
231
+ themeIntent="text"
232
+ themeSize="medium"
233
+ />
234
+ <Text
235
+ numberOfLines={1}
236
+ style={
237
+ Array [
238
+ Object {
239
+ "color": "#292a2b",
240
+ "fontSize": 12,
241
+ "fontWeight": "600",
242
+ "letterSpacing": 0.36,
243
+ "lineHeight": 20,
244
+ },
245
+ Object {
246
+ "marginTop": 4,
247
+ },
248
+ ]
249
+ }
250
+ themeFontSize="small"
251
+ themeFontWeight="semi-bold"
252
+ themeIntent="body"
253
+ >
254
+ Alerts
255
+ </Text>
256
+ </View>
257
+ <View
258
+ accessible={true}
259
+ focusable={true}
260
+ onClick={[Function]}
261
+ onResponderGrant={[Function]}
262
+ onResponderMove={[Function]}
263
+ onResponderRelease={[Function]}
264
+ onResponderTerminate={[Function]}
265
+ onResponderTerminationRequest={[Function]}
266
+ onStartShouldSetResponder={[Function]}
267
+ style={
268
+ Object {
269
+ "alignItems": "center",
270
+ "flexBasis": 0,
271
+ "flexGrow": 1,
272
+ "flexShrink": 1,
273
+ }
274
+ }
275
+ >
276
+ <HeroIcon
277
+ name="user-outlined"
278
+ style={
279
+ Object {
280
+ "color": "#292a2b",
281
+ "fontSize": 24,
282
+ }
283
+ }
284
+ testID="hero-icon-user-outlined"
285
+ themeIntent="text"
286
+ themeSize="medium"
287
+ />
288
+ <Text
289
+ numberOfLines={1}
290
+ style={
291
+ Array [
292
+ Object {
293
+ "color": "#292a2b",
294
+ "fontSize": 12,
295
+ "fontWeight": "600",
296
+ "letterSpacing": 0.36,
297
+ "lineHeight": 20,
298
+ },
299
+ Object {
300
+ "marginTop": 4,
301
+ },
302
+ ]
303
+ }
304
+ themeFontSize="small"
305
+ themeFontWeight="semi-bold"
306
+ themeIntent="body"
307
+ >
308
+ Profile
309
+ </Text>
310
+ </View>
311
+ </View>
312
+ </View>
313
+ </View>
314
+ </RNCSafeAreaProvider>
315
+ `;
@@ -0,0 +1,169 @@
1
+ import React, { ComponentProps, ReactNode } from 'react';
2
+ import {
3
+ TouchableWithoutFeedback,
4
+ StyleProp,
5
+ ViewStyle,
6
+ ViewProps,
7
+ } from 'react-native';
8
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
9
+ import { useTheme } from 'styled-components-native';
10
+ import Icon from '../Icon';
11
+ import { isHeroIcon } from '../Icon/utils';
12
+ import Typography from '../Typography';
13
+ import {
14
+ BottomBar,
15
+ BottomBarItem,
16
+ BottomBarWrapper,
17
+ BottomNavigationContainer,
18
+ BottomNavigationTab,
19
+ ContentWrapper,
20
+ } from './StyledBottomNavigation';
21
+ import { isIOS } from '../../utils/helpers';
22
+
23
+ type IconType = ComponentProps<typeof Icon>['icon'];
24
+
25
+ export type Tab<V> = {
26
+ key: V;
27
+ title?: string;
28
+ icon: IconType;
29
+ component: ReactNode;
30
+ testID?: string;
31
+ };
32
+
33
+ interface BottomNavigationType<V extends string | number, T extends Tab<V>>
34
+ extends ViewProps {
35
+ /**
36
+ * Callback which is called on tab change, receiving id of upcoming active Tab.
37
+ */
38
+ onChange: (key: V) => void;
39
+ /**
40
+ * Whether inactive tabs should be removed and unmounted in React.
41
+ * Defaults to `false`.
42
+ */
43
+ renderActiveTabOnly?: boolean;
44
+ /**
45
+ * Current selected tab key.
46
+ */
47
+ selectedTabKey: V;
48
+ /**
49
+ * List of Tab to be rendered. Each Tab must have an unique id.
50
+ */
51
+ tabs: T[];
52
+ /**
53
+ * Addditional style.
54
+ */
55
+ style?: StyleProp<ViewStyle>;
56
+ /**
57
+ * Testing id of the component.
58
+ */
59
+ testID?: string;
60
+ }
61
+
62
+ const getInactiveIcon = (icon: IconType): IconType => {
63
+ const inactiveIcon = `${icon}-outlined`;
64
+ return isHeroIcon(inactiveIcon) ? inactiveIcon : icon;
65
+ };
66
+
67
+ const BottomNavigation = <V extends string | number, T extends Tab<V>>({
68
+ onChange,
69
+ renderActiveTabOnly = false,
70
+ selectedTabKey,
71
+ tabs,
72
+ ...nativeProps
73
+ }: BottomNavigationType<V, T>): JSX.Element => {
74
+ const theme = useTheme();
75
+ const insets = useSafeAreaInsets();
76
+
77
+ /**
78
+ * List of loaded tabs, tabs will be loaded when navigated to.
79
+ */
80
+ const [loaded, setLoaded] = React.useState([selectedTabKey]);
81
+
82
+ if (!loaded.includes(selectedTabKey)) {
83
+ // Set the current tab to be loaded if it was not loaded before
84
+ setLoaded(loadedState => [...loadedState, selectedTabKey]);
85
+ }
86
+
87
+ return (
88
+ <BottomNavigationContainer {...nativeProps}>
89
+ <ContentWrapper>
90
+ {tabs.map(tab => {
91
+ const { key, component } = tab;
92
+ const active = selectedTabKey === key;
93
+
94
+ if (renderActiveTabOnly && !active) {
95
+ return null;
96
+ }
97
+
98
+ if (!loaded.includes(key)) {
99
+ // Don't render a screen if we've never navigated to it
100
+ return null;
101
+ }
102
+
103
+ return (
104
+ <BottomNavigationTab
105
+ key={key}
106
+ testID={`route-screen-${selectedTabKey}`}
107
+ pointerEvents={active ? 'auto' : 'none'}
108
+ accessibilityElementsHidden={!active}
109
+ importantForAccessibility={
110
+ active ? 'auto' : 'no-hide-descendants'
111
+ }
112
+ collapsable={false}
113
+ removeClippedSubviews={
114
+ // On iOS, set removeClippedSubviews to true only when not focused
115
+ // This is an workaround for a bug where the clipped view never re-appears.
116
+ isIOS ? selectedTabKey !== key : true
117
+ }
118
+ themeVisibility={active}
119
+ >
120
+ {component}
121
+ </BottomNavigationTab>
122
+ );
123
+ })}
124
+ </ContentWrapper>
125
+ <BottomBarWrapper themeInsets={insets}>
126
+ <BottomBar>
127
+ {tabs.map(tab => {
128
+ const { key, icon, title, testID } = tab;
129
+ const active = selectedTabKey === key;
130
+ const inactiveIcon = getInactiveIcon(icon);
131
+
132
+ return (
133
+ <TouchableWithoutFeedback
134
+ key={key}
135
+ onPress={() => {
136
+ if (key !== selectedTabKey) {
137
+ onChange(key);
138
+ }
139
+ }}
140
+ testID={testID}
141
+ >
142
+ <BottomBarItem>
143
+ <Icon
144
+ icon={active ? icon : inactiveIcon}
145
+ intent={active ? 'primary' : 'text'}
146
+ testID={`hero-icon-${icon}`}
147
+ />
148
+ {title && (
149
+ <Typography.Text
150
+ fontSize="small"
151
+ fontWeight="semi-bold"
152
+ intent={active ? 'primary' : 'body'}
153
+ style={{ marginTop: theme.space.xsmall }}
154
+ numberOfLines={1}
155
+ >
156
+ {title}
157
+ </Typography.Text>
158
+ )}
159
+ </BottomBarItem>
160
+ </TouchableWithoutFeedback>
161
+ );
162
+ })}
163
+ </BottomBar>
164
+ </BottomBarWrapper>
165
+ </BottomNavigationContainer>
166
+ );
167
+ };
168
+
169
+ export default BottomNavigation;
@@ -4,6 +4,7 @@ import styled from 'styled-components-native';
4
4
  const StyledCard = styled(View)<{}>`
5
5
  border-radius: ${({ theme }) => theme.__hd__.card.radii.default};
6
6
  padding: ${({ theme }) => theme.__hd__.card.padding.default};
7
+ overflow: hidden;
7
8
  `;
8
9
 
9
10
  export { StyledCard };
@@ -20,10 +20,11 @@ exports[`Card renders correct 1`] = `
20
20
  "borderBottomRightRadius": 12,
21
21
  "borderTopLeftRadius": 12,
22
22
  "borderTopRightRadius": 12,
23
- "paddingBottom": 16,
24
- "paddingLeft": 16,
25
- "paddingRight": 16,
26
- "paddingTop": 16,
23
+ "overflow": "hidden",
24
+ "paddingBottom": 8,
25
+ "paddingLeft": 8,
26
+ "paddingRight": 8,
27
+ "paddingTop": 8,
27
28
  },
28
29
  Object {
29
30
  "backgroundColor": "#292a2b",
@@ -8,10 +8,11 @@ exports[`StyledCard renders correct style 1`] = `
8
8
  "borderBottomRightRadius": 12,
9
9
  "borderTopLeftRadius": 12,
10
10
  "borderTopRightRadius": 12,
11
- "paddingBottom": 16,
12
- "paddingLeft": 16,
13
- "paddingRight": 16,
14
- "paddingTop": 16,
11
+ "overflow": "hidden",
12
+ "paddingBottom": 8,
13
+ "paddingLeft": 8,
14
+ "paddingRight": 8,
15
+ "paddingTop": 8,
15
16
  }
16
17
  }
17
18
  />
@@ -0,0 +1,47 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { Animated, StyleSheet } from 'react-native';
3
+ import { IconProps } from '../Icon';
4
+ import { StyledFABIcon } from './StyledFABIcon';
5
+
6
+ const AnimatedIcons = Animated.createAnimatedComponent(StyledFABIcon);
7
+
8
+ type Props = {
9
+ active?: boolean;
10
+ } & IconProps;
11
+
12
+ const AnimatedFABIcon = ({ active, ...iconProps }: Props) => {
13
+ const rotateAnimation = useRef<Animated.Value>(
14
+ new Animated.Value(active ? 1 : 0)
15
+ );
16
+ useEffect(() => {
17
+ const animation = Animated.timing(rotateAnimation.current, {
18
+ toValue: active ? 1 : 0,
19
+ useNativeDriver: true,
20
+ });
21
+
22
+ animation.start();
23
+
24
+ return () => {
25
+ animation.stop();
26
+ };
27
+ }, [active]);
28
+
29
+ const interpolatedRotateAnimation = rotateAnimation.current.interpolate({
30
+ inputRange: [0, 1],
31
+ outputRange: ['0deg', '-45deg'],
32
+ });
33
+
34
+ return (
35
+ <Animated.View
36
+ style={StyleSheet.flatten([
37
+ {
38
+ transform: [{ rotate: interpolatedRotateAnimation }],
39
+ },
40
+ ])}
41
+ >
42
+ <AnimatedIcons {...iconProps} />
43
+ </Animated.View>
44
+ );
45
+ };
46
+
47
+ export { AnimatedFABIcon };
@@ -0,0 +1,14 @@
1
+ import { TouchableHighlight, TouchableHighlightProps } from 'react-native';
2
+ import styled from 'styled-components-native';
3
+
4
+ const StyledFABContainer = styled(TouchableHighlight)<TouchableHighlightProps>`
5
+ height: ${({ theme }) => theme.__hd__.fab.sizes.height};
6
+ width: ${({ theme }) => theme.__hd__.fab.sizes.width};
7
+ background-color: ${({ theme }) => theme.__hd__.fab.colors.buttonBackground};
8
+ border-radius: 999px;
9
+ align-items: center;
10
+ justify-content: center;
11
+ overflow: hidden;
12
+ `;
13
+
14
+ export { StyledFABContainer };
@@ -0,0 +1,9 @@
1
+ import styled from 'styled-components-native';
2
+ import Icon, { IconProps } from '../Icon';
3
+
4
+ const StyledFABIcon = styled(Icon)<IconProps>`
5
+ color: ${({ theme }) => theme.__hd__.fab.colors.icon};
6
+ font-size: ${({ theme }) => theme.__hd__.fab.fontSizes.default};
7
+ `;
8
+
9
+ export { StyledFABIcon };