@hero-design/rn 8.59.0 → 8.60.1-alpha.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 (35) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +15 -0
  3. package/es/index.js +240 -116
  4. package/lib/index.js +240 -116
  5. package/package.json +2 -2
  6. package/src/components/AnimatedScroller/AnimatedFAB.tsx +99 -49
  7. package/src/components/AnimatedScroller/AnimatedScrollable.tsx +18 -3
  8. package/src/components/AnimatedScroller/__tests__/ScrollablesWithFAB.spec.tsx +30 -9
  9. package/src/components/AnimatedScroller/__tests__/__snapshots__/ScrollablesWithFAB.spec.tsx.snap +474 -447
  10. package/src/components/FAB/ActionGroup/ActionItem.tsx +3 -1
  11. package/src/components/FAB/ActionGroup/__tests__/__snapshots__/index.spec.tsx.snap +216 -211
  12. package/src/components/FAB/ActionGroup/index.tsx +34 -28
  13. package/src/components/FAB/FAB.tsx +102 -41
  14. package/src/components/FAB/StyledFAB.tsx +10 -8
  15. package/src/components/FAB/__tests__/__snapshots__/StyledFAB.spec.tsx.snap +34 -38
  16. package/src/components/FAB/__tests__/__snapshots__/index.spec.tsx.snap +191 -170
  17. package/src/components/Radio/Radio.tsx +16 -4
  18. package/src/components/Radio/RadioGroup.tsx +10 -3
  19. package/src/components/Radio/StyledRadio.tsx +20 -3
  20. package/src/components/Radio/__tests__/Radio.spec.tsx +46 -13
  21. package/src/components/Radio/__tests__/RadioGroup.spec.tsx +40 -7
  22. package/src/components/Radio/__tests__/__snapshots__/Radio.spec.tsx.snap +446 -77
  23. package/src/components/Radio/__tests__/__snapshots__/RadioGroup.spec.tsx.snap +946 -112
  24. package/src/components/Radio/types.ts +6 -1
  25. package/src/theme/__tests__/__snapshots__/index.spec.ts.snap +8 -2
  26. package/src/theme/components/radio.ts +8 -2
  27. package/types/components/AnimatedScroller/AnimatedFAB.d.ts +3 -1
  28. package/types/components/AnimatedScroller/AnimatedScrollable.d.ts +1 -1
  29. package/types/components/FAB/StyledFAB.d.ts +4 -6
  30. package/types/components/Radio/Radio.d.ts +9 -1
  31. package/types/components/Radio/RadioGroup.d.ts +5 -1
  32. package/types/components/Radio/StyledRadio.d.ts +11 -1
  33. package/types/components/Radio/index.d.ts +1 -1
  34. package/types/components/Radio/types.d.ts +1 -0
  35. package/types/theme/components/radio.d.ts +7 -1
@@ -28,58 +28,65 @@ exports[`FAB when animated is false renders StyledFABIcon 1`] = `
28
28
  onResponderTerminationRequest={[Function]}
29
29
  onStartShouldSetResponder={[Function]}
30
30
  style={
31
- [
32
- {
33
- "alignItems": "center",
34
- "alignSelf": "flex-start",
35
- "backgroundColor": "#401960",
36
- "borderRadius": 999,
37
- "elevation": 3,
38
- "flexDirection": "row",
39
- "justifyContent": "center",
40
- "padding": 20,
41
- "shadowColor": "#001f23",
42
- "shadowOffset": {
43
- "height": 2,
44
- "width": 0,
45
- },
46
- "shadowOpacity": 0.12,
47
- "shadowRadius": 4,
31
+ {
32
+ "alignItems": "center",
33
+ "alignSelf": "flex-start",
34
+ "backgroundColor": "#001f23",
35
+ "borderRadius": 999,
36
+ "bottom": undefined,
37
+ "elevation": 3,
38
+ "flexDirection": "row",
39
+ "height": 64,
40
+ "justifyContent": "center",
41
+ "padding": 20,
42
+ "shadowColor": "#001f23",
43
+ "shadowOffset": {
44
+ "height": 2,
45
+ "width": 0,
48
46
  },
49
- [
47
+ "shadowOpacity": 0.12,
48
+ "shadowRadius": 4,
49
+ "transform": [
50
50
  {
51
- "backgroundColor": "#001f23",
52
- },
53
- {
54
- "bottom": undefined,
51
+ "translateY": 0,
55
52
  },
56
53
  ],
57
- ]
54
+ }
58
55
  }
59
56
  >
60
- <HeroIcon
61
- name="add"
57
+ <View
58
+ collapsable={false}
62
59
  style={
63
- [
64
- {
65
- "color": "#001f23",
66
- "fontSize": 24,
67
- },
60
+ {
61
+ "flexDirection": "row",
62
+ "opacity": 1,
63
+ }
64
+ }
65
+ >
66
+ <HeroIcon
67
+ name="add"
68
+ style={
68
69
  [
69
70
  {
70
- "color": "#ffffff",
71
- "lineHeight": 24,
72
- "textAlign": "center",
73
- "textAlignVertical": "center",
71
+ "color": "#001f23",
72
+ "fontSize": 24,
74
73
  },
75
- undefined,
76
- ],
77
- ]
78
- }
79
- testID="styled-fab-icon"
80
- themeIntent="text"
81
- themeSize="medium"
82
- />
74
+ [
75
+ {
76
+ "color": "#ffffff",
77
+ "lineHeight": 24,
78
+ "textAlign": "center",
79
+ "textAlignVertical": "center",
80
+ },
81
+ undefined,
82
+ ],
83
+ ]
84
+ }
85
+ testID="styled-fab-icon"
86
+ themeIntent="text"
87
+ themeSize="medium"
88
+ />
89
+ </View>
83
90
  </View>
84
91
  <View
85
92
  pointerEvents="box-none"
@@ -132,86 +139,93 @@ exports[`FAB when animated is true renders animatedFABIcon 1`] = `
132
139
  onResponderTerminationRequest={[Function]}
133
140
  onStartShouldSetResponder={[Function]}
134
141
  style={
135
- [
136
- {
137
- "alignItems": "center",
138
- "alignSelf": "flex-start",
139
- "backgroundColor": "#401960",
140
- "borderRadius": 999,
141
- "elevation": 3,
142
- "flexDirection": "row",
143
- "justifyContent": "center",
144
- "padding": 20,
145
- "shadowColor": "#001f23",
146
- "shadowOffset": {
147
- "height": 2,
148
- "width": 0,
149
- },
150
- "shadowOpacity": 0.12,
151
- "shadowRadius": 4,
142
+ {
143
+ "alignItems": "center",
144
+ "alignSelf": "flex-start",
145
+ "backgroundColor": "#001f23",
146
+ "borderRadius": 999,
147
+ "bottom": undefined,
148
+ "elevation": 3,
149
+ "flexDirection": "row",
150
+ "height": 64,
151
+ "justifyContent": "center",
152
+ "padding": 20,
153
+ "shadowColor": "#001f23",
154
+ "shadowOffset": {
155
+ "height": 2,
156
+ "width": 0,
152
157
  },
153
- [
154
- {
155
- "backgroundColor": "#001f23",
156
- },
158
+ "shadowOpacity": 0.12,
159
+ "shadowRadius": 4,
160
+ "transform": [
157
161
  {
158
- "bottom": undefined,
162
+ "translateY": 0,
159
163
  },
160
164
  ],
161
- ]
165
+ }
162
166
  }
163
167
  >
164
168
  <View
169
+ collapsable={false}
165
170
  style={
166
- [
167
- {},
168
- [
169
- {
170
- "alignItems": "center",
171
- "height": 24,
172
- "justifyContent": "center",
173
- "width": 24,
174
- },
175
- undefined,
176
- ],
177
- ]
171
+ {
172
+ "flexDirection": "row",
173
+ "opacity": 1,
174
+ }
178
175
  }
179
176
  >
180
177
  <View
181
- collapsable={false}
182
178
  style={
183
- {
184
- "transform": [
179
+ [
180
+ {},
181
+ [
185
182
  {
186
- "rotate": "0deg",
183
+ "alignItems": "center",
184
+ "height": 24,
185
+ "justifyContent": "center",
186
+ "width": 24,
187
187
  },
188
+ undefined,
188
189
  ],
189
- }
190
+ ]
190
191
  }
191
192
  >
192
- <HeroIcon
193
- name="add"
193
+ <View
194
+ collapsable={false}
194
195
  style={
195
- [
196
- {
197
- "color": "#001f23",
198
- "fontSize": 16,
199
- },
200
- [
196
+ {
197
+ "transform": [
201
198
  {
202
- "color": "#ffffff",
203
- "lineHeight": 24,
204
- "textAlign": "center",
205
- "textAlignVertical": "center",
199
+ "rotate": "0deg",
206
200
  },
207
- {},
208
201
  ],
209
- ]
202
+ }
210
203
  }
211
- testID="animated-fab-icon"
212
- themeIntent="text"
213
- themeSize="xsmall"
214
- />
204
+ >
205
+ <HeroIcon
206
+ name="add"
207
+ style={
208
+ [
209
+ {
210
+ "color": "#001f23",
211
+ "fontSize": 16,
212
+ },
213
+ [
214
+ {
215
+ "color": "#ffffff",
216
+ "lineHeight": 24,
217
+ "textAlign": "center",
218
+ "textAlignVertical": "center",
219
+ },
220
+ {},
221
+ ],
222
+ ]
223
+ }
224
+ testID="animated-fab-icon"
225
+ themeIntent="text"
226
+ themeSize="xsmall"
227
+ />
228
+ </View>
215
229
  </View>
216
230
  </View>
217
231
  </View>
@@ -266,63 +280,96 @@ exports[`FAB when title has value renders correctly 1`] = `
266
280
  onResponderTerminationRequest={[Function]}
267
281
  onStartShouldSetResponder={[Function]}
268
282
  style={
269
- [
270
- {
271
- "alignItems": "center",
272
- "alignSelf": "flex-start",
273
- "backgroundColor": "#401960",
274
- "borderRadius": 999,
275
- "elevation": 3,
276
- "flexDirection": "row",
277
- "justifyContent": "center",
278
- "padding": 20,
279
- "shadowColor": "#001f23",
280
- "shadowOffset": {
281
- "height": 2,
282
- "width": 0,
283
- },
284
- "shadowOpacity": 0.12,
285
- "shadowRadius": 4,
283
+ {
284
+ "alignItems": "center",
285
+ "alignSelf": "flex-start",
286
+ "backgroundColor": "#001f23",
287
+ "borderRadius": 999,
288
+ "bottom": undefined,
289
+ "elevation": 3,
290
+ "flexDirection": "row",
291
+ "height": 64,
292
+ "justifyContent": "center",
293
+ "padding": 20,
294
+ "shadowColor": "#001f23",
295
+ "shadowOffset": {
296
+ "height": 2,
297
+ "width": 0,
286
298
  },
287
- [
288
- {
289
- "backgroundColor": "#001f23",
290
- },
299
+ "shadowOpacity": 0.12,
300
+ "shadowRadius": 4,
301
+ "transform": [
291
302
  {
292
- "bottom": undefined,
303
+ "translateY": 0,
293
304
  },
294
305
  ],
295
- ]
306
+ }
296
307
  }
297
308
  >
298
309
  <View
310
+ collapsable={false}
299
311
  style={
300
- [
301
- {},
302
- [
303
- {
304
- "alignItems": "center",
305
- "height": 24,
306
- "justifyContent": "center",
307
- "width": 24,
308
- },
309
- undefined,
310
- ],
311
- ]
312
+ {
313
+ "flexDirection": "row",
314
+ "opacity": 1,
315
+ }
312
316
  }
313
317
  >
314
- <HeroIcon
315
- name="pencil"
318
+ <View
319
+ style={
320
+ [
321
+ {},
322
+ [
323
+ {
324
+ "alignItems": "center",
325
+ "height": 24,
326
+ "justifyContent": "center",
327
+ "width": 24,
328
+ },
329
+ undefined,
330
+ ],
331
+ ]
332
+ }
333
+ >
334
+ <HeroIcon
335
+ name="pencil"
336
+ style={
337
+ [
338
+ {
339
+ "color": "#001f23",
340
+ "fontSize": 16,
341
+ },
342
+ [
343
+ {
344
+ "color": "#ffffff",
345
+ "lineHeight": 24,
346
+ "textAlign": "center",
347
+ "textAlignVertical": "center",
348
+ },
349
+ undefined,
350
+ ],
351
+ ]
352
+ }
353
+ testID="styled-fab-icon"
354
+ themeIntent="text"
355
+ themeSize="xsmall"
356
+ />
357
+ </View>
358
+ <Text
359
+ allowFontScaling={false}
316
360
  style={
317
361
  [
318
362
  {
319
363
  "color": "#001f23",
364
+ "fontFamily": "BeVietnamPro-Regular",
320
365
  "fontSize": 16,
366
+ "letterSpacing": 0.48,
367
+ "lineHeight": 24,
321
368
  },
322
369
  [
323
370
  {
324
371
  "color": "#ffffff",
325
- "lineHeight": 24,
372
+ "marginHorizontal": 8,
326
373
  "textAlign": "center",
327
374
  "textAlignVertical": "center",
328
375
  },
@@ -330,39 +377,13 @@ exports[`FAB when title has value renders correctly 1`] = `
330
377
  ],
331
378
  ]
332
379
  }
333
- testID="styled-fab-icon"
334
- themeIntent="text"
335
- themeSize="xsmall"
336
- />
380
+ themeIntent="body"
381
+ themeTypeface="neutral"
382
+ themeVariant="regular"
383
+ >
384
+ Shout out
385
+ </Text>
337
386
  </View>
338
- <Text
339
- allowFontScaling={false}
340
- style={
341
- [
342
- {
343
- "color": "#001f23",
344
- "fontFamily": "BeVietnamPro-Regular",
345
- "fontSize": 16,
346
- "letterSpacing": 0.48,
347
- "lineHeight": 24,
348
- },
349
- [
350
- {
351
- "color": "#ffffff",
352
- "marginHorizontal": 8,
353
- "textAlign": "center",
354
- "textAlignVertical": "center",
355
- },
356
- undefined,
357
- ],
358
- ]
359
- }
360
- themeIntent="body"
361
- themeTypeface="neutral"
362
- themeVariant="regular"
363
- >
364
- Shout out
365
- </Text>
366
387
  </View>
367
388
  <View
368
389
  pointerEvents="box-none"
@@ -1,9 +1,8 @@
1
- import React from 'react';
2
1
  import type { ReactElement } from 'react';
2
+ import React from 'react';
3
3
  import type { StyleProp, ViewStyle } from 'react-native';
4
4
 
5
- import List from '../List';
6
- import { Circle, InnerCircle } from './StyledRadio';
5
+ import { Circle, InnerCircle, StyledRadio } from './StyledRadio';
7
6
 
8
7
  export interface RadioProps {
9
8
  /**
@@ -22,10 +21,18 @@ export interface RadioProps {
22
21
  * Additional style.
23
22
  */
24
23
  style?: StyleProp<ViewStyle>;
24
+ /**
25
+ * Radio subtext.
26
+ */
27
+ subText?: string;
25
28
  /**
26
29
  * Testing id of the component.
27
30
  */
28
31
  testID?: string;
32
+ /**
33
+ * Idle background color of the Radio.
34
+ */
35
+ inactiveIntent?: 'light' | 'dark';
29
36
  }
30
37
 
31
38
  const RadioCircle = ({
@@ -42,15 +49,20 @@ const Radio = ({
42
49
  checked = false,
43
50
  onPress,
44
51
  style,
52
+ subText,
45
53
  testID,
54
+ inactiveIntent = 'light',
46
55
  }: RadioProps): ReactElement => (
47
- <List.BasicItem
56
+ <StyledRadio
48
57
  onPress={onPress}
49
58
  selected={checked}
50
59
  title={text}
60
+ subtitle={subText}
51
61
  suffix={<RadioCircle checked={checked} text={text} />}
52
62
  style={style}
53
63
  testID={testID}
64
+ themeIntent={inactiveIntent}
65
+ themeChecked={checked}
54
66
  />
55
67
  );
56
68
 
@@ -1,7 +1,7 @@
1
- import React from 'react';
2
- import { View } from 'react-native';
3
1
  import type { ReactElement } from 'react';
2
+ import React from 'react';
4
3
  import type { StyleProp, ViewStyle } from 'react-native';
4
+ import { View } from 'react-native';
5
5
  import Radio from './Radio';
6
6
  import { Spacer } from './StyledRadio';
7
7
  import type { OptionType } from './types';
@@ -32,6 +32,10 @@ export interface RadioGroupProps<T> {
32
32
  * Testing id of the component.
33
33
  */
34
34
  testID?: string;
35
+ /**
36
+ * Idle background color of the Radio.
37
+ */
38
+ inactiveIntent?: 'light' | 'dark';
35
39
  }
36
40
 
37
41
  function getKey<T>(
@@ -58,15 +62,18 @@ const RadioGroup = <T,>({
58
62
  keyExtractor,
59
63
  style,
60
64
  testID,
65
+ inactiveIntent = 'light',
61
66
  }: RadioGroupProps<T>): ReactElement => (
62
67
  <View style={style} testID={testID}>
63
68
  {options.map((option, index) => (
64
69
  <React.Fragment key={getKey(option, index, keyExtractor)}>
65
- {index !== 0 && <Spacer />}
70
+ {index !== 0 && <Spacer themeIntent={inactiveIntent} />}
66
71
  <Radio
67
72
  text={option.text}
73
+ subText={option.subText}
68
74
  checked={option.value === value}
69
75
  onPress={() => onPress(option.value)}
76
+ inactiveIntent={inactiveIntent}
70
77
  />
71
78
  </React.Fragment>
72
79
  ))}
@@ -1,5 +1,8 @@
1
1
  import { View } from 'react-native';
2
2
  import styled from '@emotion/native';
3
+ import List from '../List';
4
+
5
+ type RadioIntent = 'light' | 'dark';
3
6
 
4
7
  const Circle = styled(View)(({ theme }) => ({
5
8
  height: theme.__hd__.radio.sizes.circle,
@@ -18,8 +21,22 @@ const InnerCircle = styled(View)(({ theme }) => ({
18
21
  backgroundColor: theme.__hd__.radio.colors.circle,
19
22
  }));
20
23
 
21
- const Spacer = styled(View)(({ theme }) => ({
22
- marginTop: theme.__hd__.radio.space.groupTopMargin,
24
+ const Spacer = styled(View)<{ themeIntent: RadioIntent }>(
25
+ ({ theme, themeIntent }) => ({
26
+ marginTop:
27
+ themeIntent === 'light'
28
+ ? theme.__hd__.radio.space.groupTopMarginSmall
29
+ : theme.__hd__.radio.space.groupTopMarginMedium,
30
+ })
31
+ );
32
+
33
+ const StyledRadio = styled(List.Item)<{
34
+ themeIntent: RadioIntent;
35
+ themeChecked: boolean;
36
+ }>(({ theme, themeIntent, themeChecked }) => ({
37
+ backgroundColor: themeChecked
38
+ ? theme.__hd__.radio.colors.checked
39
+ : theme.__hd__.radio.colors.intents[themeIntent],
23
40
  }));
24
41
 
25
- export { Circle, InnerCircle, Spacer };
42
+ export { Circle, InnerCircle, Spacer, StyledRadio };
@@ -4,24 +4,57 @@ import renderWithTheme from '../../../testHelpers/renderWithTheme';
4
4
  import Radio from '../Radio';
5
5
 
6
6
  describe('rendering', () => {
7
- it('renders correctly when checked', () => {
8
- const { getByText, queryAllByTestId, toJSON } = renderWithTheme(
9
- <Radio text="Option A" onPress={jest.fn} checked />
10
- );
7
+ it.each`
8
+ inactiveIntent
9
+ ${'light'}
10
+ ${'dark'}
11
+ `(
12
+ 'renders correctly when checked with inactiveIntent=$inactiveIntent',
13
+ ({ inactiveIntent }) => {
14
+ const { getByText, queryAllByTestId, toJSON } = renderWithTheme(
15
+ <Radio
16
+ inactiveIntent={inactiveIntent}
17
+ text="Option A"
18
+ onPress={jest.fn}
19
+ checked
20
+ />
21
+ );
11
22
 
12
- expect(getByText('Option A')).toBeDefined();
13
- expect(queryAllByTestId('Option A-selected-circle')).toHaveLength(1);
14
- expect(toJSON()).toMatchSnapshot();
15
- });
23
+ expect(getByText('Option A')).toBeDefined();
24
+ expect(queryAllByTestId('Option A-selected-circle')).toHaveLength(1);
25
+ expect(toJSON()).toMatchSnapshot();
26
+ }
27
+ );
16
28
 
17
- it('renders correctly when not checked', () => {
18
- const { getByText, toJSON, queryAllByTestId } = renderWithTheme(
19
- <Radio text="Option A" onPress={jest.fn} checked={false} />
29
+ it.each`
30
+ inactiveIntent
31
+ ${'light'}
32
+ ${'dark'}
33
+ `(
34
+ 'renders correctly when not checked with inactiveIntent=$inactiveIntent',
35
+ ({ inactiveIntent }) => {
36
+ const { getByText, toJSON, queryAllByTestId } = renderWithTheme(
37
+ <Radio
38
+ inactiveIntent={inactiveIntent}
39
+ text="Option A"
40
+ onPress={jest.fn}
41
+ checked={false}
42
+ />
43
+ );
44
+
45
+ expect(getByText('Option A')).toBeDefined();
46
+ expect(queryAllByTestId('Option A-selected-circle')).toHaveLength(0);
47
+ expect(toJSON()).toMatchSnapshot();
48
+ }
49
+ );
50
+
51
+ it('allows rendering of subtext', () => {
52
+ const { getByText } = renderWithTheme(
53
+ <Radio text="Option A" subText="Option label" onPress={jest.fn} checked />
20
54
  );
21
55
 
22
56
  expect(getByText('Option A')).toBeDefined();
23
- expect(queryAllByTestId('Option A-selected-circle')).toHaveLength(0);
24
- expect(toJSON()).toMatchSnapshot();
57
+ expect(getByText('Option label')).toBeDefined();
25
58
  });
26
59
  });
27
60