@hero-design/rn 7.16.2 → 7.17.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.
Files changed (122) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/es/index.js +331 -259
  3. package/lib/index.js +330 -258
  4. package/package.json +2 -2
  5. package/src/components/Accordion/__tests__/__snapshots__/AccordionItem.spec.tsx.snap +12 -12
  6. package/src/components/Accordion/__tests__/__snapshots__/index.spec.tsx.snap +18 -18
  7. package/src/components/Alert/__tests__/__snapshots__/index.spec.tsx.snap +26 -26
  8. package/src/components/Avatar/__tests__/__snapshots__/StyledAvatar.spec.tsx.snap +3 -3
  9. package/src/components/Avatar/__tests__/__snapshots__/index.spec.tsx.snap +2 -2
  10. package/src/components/Badge/__tests__/__snapshots__/Badge.spec.tsx.snap +1 -1
  11. package/src/components/Badge/__tests__/__snapshots__/Status.spec.tsx.snap +2 -2
  12. package/src/components/BottomNavigation/__tests__/__snapshots__/index.spec.tsx.snap +9 -9
  13. package/src/components/BottomSheet/__tests__/__snapshots__/index.spec.tsx.snap +12 -12
  14. package/src/components/Button/LoadingIndicator/__tests__/__snapshots__/StyledLoadingIndicator.spec.tsx.snap +2 -2
  15. package/src/components/Button/LoadingIndicator/__tests__/__snapshots__/index.spec.tsx.snap +6 -6
  16. package/src/components/Button/UtilityButton/__tests__/__snapshots__/index.spec.tsx.snap +6 -6
  17. package/src/components/Button/__tests__/__snapshots__/IconButton.spec.tsx.snap +1 -1
  18. package/src/components/Button/__tests__/__snapshots__/StyledButton.spec.tsx.snap +67 -67
  19. package/src/components/Calendar/__tests__/__snapshots__/CalendarRowItem.spec.tsx.snap +12 -12
  20. package/src/components/Card/__tests__/__snapshots__/StyledCard.spec.tsx.snap +1 -1
  21. package/src/components/Checkbox/__tests__/__snapshots__/StyledCheckbox.spec.tsx.snap +1 -1
  22. package/src/components/Checkbox/__tests__/__snapshots__/index.spec.tsx.snap +2 -2
  23. package/src/components/ContentNavigator/__tests__/__snapshots__/StyledContentNavigator.spec.tsx.snap +1 -1
  24. package/src/components/ContentNavigator/__tests__/__snapshots__/index.spec.tsx.snap +6 -6
  25. package/src/components/DatePicker/__tests__/__snapshots__/DatePickerAndroid.spec.tsx.snap +5 -5
  26. package/src/components/DatePicker/__tests__/__snapshots__/DatePickerIOS.spec.tsx.snap +12 -12
  27. package/src/components/Divider/__tests__/__snapshots__/StyledDivider.spec.tsx.snap +12 -12
  28. package/src/components/Drawer/__tests__/__snapshots__/index.spec.tsx.snap +3 -3
  29. package/src/components/Empty/__tests__/__snapshots__/index.spec.tsx.snap +3 -3
  30. package/src/components/FAB/ActionGroup/__tests__/__snapshots__/index.spec.tsx.snap +28 -28
  31. package/src/components/FAB/__tests__/__snapshots__/AnimatedFABIcon.spec.tsx.snap +2 -2
  32. package/src/components/FAB/__tests__/__snapshots__/StyledFAB.spec.tsx.snap +3 -3
  33. package/src/components/FAB/__tests__/__snapshots__/index.spec.tsx.snap +9 -9
  34. package/src/components/Icon/__tests__/__snapshots__/index.spec.tsx.snap +3 -3
  35. package/src/components/List/BasicListItem.tsx +8 -4
  36. package/src/components/List/__tests__/__snapshots__/BasicListItem.spec.tsx.snap +3 -3
  37. package/src/components/List/__tests__/__snapshots__/ListItem.spec.tsx.snap +20 -20
  38. package/src/components/List/__tests__/__snapshots__/StyledBasicListItem.spec.tsx.snap +6 -6
  39. package/src/components/List/__tests__/__snapshots__/StyledListItem.spec.tsx.snap +12 -12
  40. package/src/components/PinInput/__tests__/__snapshots__/PinCell.spec.tsx.snap +4 -4
  41. package/src/components/PinInput/__tests__/__snapshots__/index.spec.tsx.snap +22 -22
  42. package/src/components/Progress/ProgressCircle.tsx +25 -22
  43. package/src/components/Progress/StyledProgressCircle.tsx +33 -28
  44. package/src/components/Progress/__tests__/__snapshots__/index.spec.js.snap +102 -92
  45. package/src/components/Radio/__tests__/__snapshots__/Radio.spec.tsx.snap +5 -5
  46. package/src/components/Radio/__tests__/__snapshots__/RadioGroup.spec.tsx.snap +6 -6
  47. package/src/components/Radio/__tests__/__snapshots__/StyledRadio.spec.tsx.snap +3 -3
  48. package/src/components/RichTextEditor/__tests__/__snapshots__/EditorToolbar.spec.tsx.snap +11 -11
  49. package/src/components/RichTextEditor/__tests__/__snapshots__/RichTextEditor.spec.tsx.snap +6 -6
  50. package/src/components/SectionHeading/__tests__/__snapshots__/StyledHeading.spec.tsx.snap +1 -1
  51. package/src/components/SectionHeading/__tests__/__snapshots__/index.spec.tsx.snap +9 -9
  52. package/src/components/Select/MultiSelect/Option.tsx +20 -11
  53. package/src/components/Select/MultiSelect/OptionList.tsx +47 -41
  54. package/src/components/Select/MultiSelect/__tests__/OptionList.spec.tsx +25 -14
  55. package/src/components/Select/MultiSelect/__tests__/__snapshots__/Option.spec.tsx.snap +6 -4
  56. package/src/components/Select/MultiSelect/__tests__/__snapshots__/OptionList.spec.tsx.snap +1638 -134
  57. package/src/components/Select/MultiSelect/__tests__/__snapshots__/index.spec.tsx.snap +5312 -366
  58. package/src/components/Select/MultiSelect/__tests__/index.spec.tsx +122 -1
  59. package/src/components/Select/MultiSelect/index.tsx +26 -36
  60. package/src/components/Select/SingleSelect/Option.tsx +19 -3
  61. package/src/components/Select/SingleSelect/OptionList.tsx +47 -39
  62. package/src/components/Select/SingleSelect/__tests__/OptionList.spec.tsx +23 -12
  63. package/src/components/Select/SingleSelect/__tests__/__snapshots__/Option.spec.tsx.snap +5 -3
  64. package/src/components/Select/SingleSelect/__tests__/__snapshots__/OptionList.spec.tsx.snap +1632 -128
  65. package/src/components/Select/SingleSelect/__tests__/__snapshots__/index.spec.tsx.snap +4932 -302
  66. package/src/components/Select/SingleSelect/__tests__/index.spec.tsx +117 -1
  67. package/src/components/Select/SingleSelect/index.tsx +26 -37
  68. package/src/components/Select/StyledOptionList.tsx +43 -44
  69. package/src/components/Select/StyledSelect.tsx +7 -3
  70. package/src/components/Select/__tests__/StyledSelect.spec.tsx +1 -9
  71. package/src/components/Select/__tests__/__snapshots__/StyledSelect.spec.tsx.snap +2 -15
  72. package/src/components/Select/__tests__/helpers.spec.tsx +74 -0
  73. package/src/components/Select/helpers.tsx +87 -4
  74. package/src/components/Select/types.ts +99 -0
  75. package/src/components/Spinner/__tests__/__snapshots__/AnimatedSpinner.spec.tsx.snap +4 -4
  76. package/src/components/Spinner/__tests__/__snapshots__/StyledSpinner.spec.tsx.snap +8 -8
  77. package/src/components/Spinner/__tests__/__snapshots__/index.spec.tsx.snap +4 -4
  78. package/src/components/Switch/__tests__/__snapshots__/StyledHeading.spec.tsx.snap +1 -1
  79. package/src/components/Switch/__tests__/__snapshots__/index.spec.tsx.snap +2 -2
  80. package/src/components/Tabs/__tests__/__snapshots__/ScrollableTabs.spec.tsx.snap +6 -6
  81. package/src/components/Tabs/__tests__/__snapshots__/index.spec.tsx.snap +8 -8
  82. package/src/components/Tag/__tests__/__snapshots__/Tag.spec.tsx.snap +8 -8
  83. package/src/components/TextInput/__tests__/__snapshots__/StyledTextInput.spec.tsx.snap +50 -50
  84. package/src/components/TextInput/__tests__/__snapshots__/index.spec.tsx.snap +241 -85
  85. package/src/components/TextInput/__tests__/index.spec.tsx +29 -8
  86. package/src/components/TextInput/index.tsx +18 -7
  87. package/src/components/TimePicker/__tests__/__snapshots__/TimePickerAndroid.spec.tsx.snap +5 -5
  88. package/src/components/TimePicker/__tests__/__snapshots__/TimePickerIOS.spec.tsx.snap +12 -12
  89. package/src/components/Toast/__tests__/__snapshots__/Toast.spec.tsx.snap +22 -22
  90. package/src/components/Toolbar/__tests__/__snapshots__/ToolbarGroup.spec.tsx.snap +12 -12
  91. package/src/components/Toolbar/__tests__/__snapshots__/ToolbarItem.spec.tsx.snap +8 -8
  92. package/src/components/Typography/Text/__tests__/__snapshots__/StyledText.spec.tsx.snap +13 -13
  93. package/src/theme/__tests__/__snapshots__/index.spec.ts.snap +145 -146
  94. package/src/theme/components/alert.ts +3 -3
  95. package/src/theme/components/badge.ts +1 -1
  96. package/src/theme/components/card.ts +4 -4
  97. package/src/theme/components/list.ts +4 -4
  98. package/src/theme/components/pinInput.ts +2 -2
  99. package/src/theme/components/progress.ts +5 -5
  100. package/src/theme/components/select.ts +3 -3
  101. package/src/theme/components/toast.ts +3 -3
  102. package/src/theme/global/colors.ts +40 -39
  103. package/src/types.ts +7 -1
  104. package/types/components/List/BasicListItem.d.ts +1 -1
  105. package/types/components/Progress/StyledProgressCircle.d.ts +12 -6
  106. package/types/components/Select/MultiSelect/Option.d.ts +4 -2
  107. package/types/components/Select/MultiSelect/OptionList.d.ts +6 -7
  108. package/types/components/Select/MultiSelect/index.d.ts +5 -5
  109. package/types/components/Select/SingleSelect/Option.d.ts +4 -2
  110. package/types/components/Select/SingleSelect/OptionList.d.ts +6 -7
  111. package/types/components/Select/SingleSelect/index.d.ts +5 -5
  112. package/types/components/Select/StyledOptionList.d.ts +10 -16
  113. package/types/components/Select/StyledSelect.d.ts +8 -2
  114. package/types/components/Select/__tests__/helpers.spec.d.ts +1 -0
  115. package/types/components/Select/helpers.d.ts +14 -2
  116. package/types/components/Select/index.d.ts +1 -1
  117. package/types/components/Select/types.d.ts +32 -7
  118. package/types/components/TextInput/index.d.ts +4 -2
  119. package/types/theme/components/progress.d.ts +1 -2
  120. package/types/theme/components/select.d.ts +3 -3
  121. package/types/types.d.ts +2 -1
  122. package/src/components/Select/types.tsx +0 -52
@@ -2,6 +2,9 @@ import { fireEvent } from '@testing-library/react-native';
2
2
  import React from 'react';
3
3
  import renderWithTheme from '../../../../testHelpers/renderWithTheme';
4
4
  import MultiSelect from '..';
5
+ import Typography from '../../../Typography';
6
+ import List from '../../../List';
7
+ import { ListRenderOptionInfo } from '../../types';
5
8
 
6
9
  const options = [
7
10
  { text: 'Monday', value: 'mon' },
@@ -10,9 +13,65 @@ const options = [
10
13
  { text: 'Thursday', value: 'thu' },
11
14
  { text: 'Friday', value: 'fri' },
12
15
  { text: 'Saturday', value: 'sat' },
13
- { text: 'Sunday', value: 'sun' },
16
+ { text: 'Sunday', value: 'sun', disabled: true },
14
17
  ];
15
18
 
19
+ const sections = [
20
+ { category: 'A', data: [{ text: 'A1', value: 'a1' }] },
21
+ {
22
+ category: 'B',
23
+ data: [
24
+ { text: 'B1', value: 'b1' },
25
+ { text: 'B2', value: 'b2' },
26
+ ],
27
+ },
28
+ ];
29
+
30
+ type CustomOptionType = {
31
+ text: string;
32
+ value: string;
33
+ role: string;
34
+ };
35
+
36
+ const collaboratorSections = [
37
+ {
38
+ category: 'D',
39
+ data: [
40
+ { text: 'Daniel', value: 'daniel', role: 'Senior Developer' },
41
+ { text: 'Daemon', value: 'daemon', role: 'Manager' },
42
+ ],
43
+ },
44
+ {
45
+ category: 'J',
46
+ data: [
47
+ { text: 'Jennifer', value: 'jennifer', role: 'UX Designer' },
48
+ { text: 'Josh ', value: 'josh', role: 'Junior Developer' },
49
+ ],
50
+ },
51
+ ];
52
+
53
+ const renderMultipleOption = ({
54
+ item,
55
+ selected,
56
+ onPress,
57
+ }: ListRenderOptionInfo<string, CustomOptionType>) => (
58
+ <List.BasicItem
59
+ selected={selected}
60
+ suffix={selected ? 'checkmark' : undefined}
61
+ onPress={onPress}
62
+ title={
63
+ <>
64
+ <Typography.Text fontSize="large" fontWeight="semi-bold">
65
+ {item.text}
66
+ </Typography.Text>
67
+ <Typography.Text fontSize="large" intent="subdued">
68
+ {item.role}
69
+ </Typography.Text>
70
+ </>
71
+ }
72
+ />
73
+ );
74
+
16
75
  describe('rendering', () => {
17
76
  it('renders correctly when bottom sheet is NOT visible', () => {
18
77
  const { queryAllByText, toJSON, getByTestId } = renderWithTheme(
@@ -53,6 +112,68 @@ describe('rendering', () => {
53
112
  expect(getByText('Sunday')).toBeDefined();
54
113
  expect(getByText('Confirm')).toBeDefined();
55
114
  });
115
+
116
+ it('renders correctly when input is loading', () => {
117
+ const { toJSON, getByTestId } = renderWithTheme(
118
+ <MultiSelect
119
+ label="Allow notifications"
120
+ footerLabel="Confirm"
121
+ options={options}
122
+ value={['mon', 'tue']}
123
+ inputProps={{ loading: true }}
124
+ onConfirm={jest.fn()}
125
+ />
126
+ );
127
+
128
+ expect(toJSON()).toMatchSnapshot();
129
+ expect(getByTestId('input-suffix')).toHaveProp('name', 'loading');
130
+ });
131
+
132
+ it('renders correctly when receives sections', () => {
133
+ const { queryAllByText, getByText, toJSON, getByTestId } = renderWithTheme(
134
+ <MultiSelect
135
+ label="Allow notifications"
136
+ footerLabel="Confirm"
137
+ options={sections}
138
+ value={['b1', 'b2']}
139
+ onConfirm={jest.fn()}
140
+ />
141
+ );
142
+ fireEvent.press(getByTestId('text-input'));
143
+
144
+ expect(toJSON()).toMatchSnapshot();
145
+ expect(queryAllByText('Allow notifications')).toHaveLength(2);
146
+ expect(getByText('A')).toBeTruthy();
147
+ expect(getByText('A1')).toBeTruthy();
148
+ expect(getByText('B')).toBeTruthy();
149
+ expect(getByText('B1')).toBeTruthy();
150
+ expect(getByText('B2')).toBeTruthy();
151
+ expect(getByText('Confirm')).toBeDefined();
152
+ });
153
+
154
+ it('allows custom renderer', () => {
155
+ const { getByText, toJSON, getByTestId } = renderWithTheme(
156
+ <MultiSelect<string, CustomOptionType>
157
+ label="Choose collaborators"
158
+ footerLabel="Confirm"
159
+ options={collaboratorSections}
160
+ renderOption={renderMultipleOption}
161
+ value={[]}
162
+ onConfirm={jest.fn()}
163
+ />
164
+ );
165
+ fireEvent.press(getByTestId('text-input'));
166
+
167
+ expect(toJSON()).toMatchSnapshot();
168
+ expect(getByText('Daniel')).toBeTruthy();
169
+ expect(getByText('Senior Developer')).toBeTruthy();
170
+ expect(getByText('Daemon')).toBeTruthy();
171
+ expect(getByText('Manager')).toBeTruthy();
172
+ expect(getByText('Jennifer')).toBeTruthy();
173
+ expect(getByText('UX Designer')).toBeTruthy();
174
+ expect(getByText('Josh')).toBeTruthy();
175
+ expect(getByText('Junior Developer')).toBeTruthy();
176
+ });
56
177
  });
57
178
 
58
179
  describe('behavior', () => {
@@ -1,37 +1,41 @@
1
- import React, { useEffect, useState } from 'react';
2
- import { TouchableOpacity, Keyboard, KeyboardEvent, View } from 'react-native';
1
+ import React, { useState } from 'react';
2
+ import { TouchableOpacity, View } from 'react-native';
3
3
 
4
- import { SelectProps } from '../types';
4
+ import { OptionType, SelectProps } from '../types';
5
5
  import BottomSheet from '../../BottomSheet';
6
6
  import Footer from '../Footer';
7
7
  import OptionList from './OptionList';
8
8
  import TextInput from '../../TextInput';
9
9
  import { StyledSearchBar } from '../StyledSelect';
10
+ import { toFlatOptions, toSections, useKeyboard } from '../helpers';
10
11
 
11
- export interface MultiSelectProps<T> extends SelectProps<T> {
12
+ export interface MultiSelectProps<V, T extends OptionType<V> = OptionType<V>>
13
+ extends SelectProps<V, T> {
12
14
  /**
13
15
  * Current selected value.
14
16
  */
15
- value: T[];
17
+ value: V[];
16
18
  /**
17
19
  * event handler for footer button.
18
20
  */
19
- onConfirm: (value: T[]) => void;
21
+ onConfirm: (value: V[]) => void;
20
22
  /**
21
23
  * Footer label.
22
24
  */
23
25
  footerLabel: string;
24
26
  }
25
27
 
26
- function MultiSelect<T>({
28
+ function MultiSelect<V, T extends OptionType<V>>({
27
29
  footerLabel,
28
30
  label,
29
- loading,
31
+ loading = false,
32
+ inputProps,
30
33
  onConfirm,
31
34
  onDimiss,
32
35
  onEndReached,
33
36
  onQueryChange,
34
37
  options,
38
+ renderOption,
35
39
  query,
36
40
  error,
37
41
  editable = true,
@@ -40,41 +44,24 @@ function MultiSelect<T>({
40
44
  style,
41
45
  testID,
42
46
  value,
43
- }: MultiSelectProps<T>) {
47
+ }: MultiSelectProps<V, T>) {
48
+ const { isKeyboardVisible, keyboardHeight } = useKeyboard();
44
49
  const [open, setOpen] = useState(false);
45
50
  const [selectingValue, setSelectingValue] = useState(value);
46
- const displayedValue = options
51
+ const sections = toSections(options);
52
+ const flatOptions = toFlatOptions(options);
53
+ const displayedValue = flatOptions
47
54
  .filter(opt => value.includes(opt.value))
48
55
  .map(opt => opt.text)
49
56
  .join(', ');
50
57
 
51
- const [isKeyboardVisible, setKeyboardVisible] = useState(false);
52
- const [keyboardHeight, setKeyboardHeight] = useState(0);
53
-
54
- useEffect(() => {
55
- const keyboardDidShowListener = Keyboard.addListener(
56
- 'keyboardDidShow',
57
- (e: KeyboardEvent) => {
58
- setKeyboardVisible(true);
59
- setKeyboardHeight(e.endCoordinates.height);
60
- }
61
- );
62
- const keyboardDidHideListener = Keyboard.addListener(
63
- 'keyboardDidHide',
64
- () => {
65
- setKeyboardVisible(false);
66
- }
67
- );
68
-
69
- return () => {
70
- keyboardDidHideListener.remove();
71
- keyboardDidShowListener.remove();
72
- };
73
- }, []);
74
-
75
58
  return (
76
59
  <>
77
- <View pointerEvents={!editable || disabled ? 'none' : 'auto'}>
60
+ <View
61
+ pointerEvents={
62
+ !editable || disabled || inputProps?.loading ? 'none' : 'auto'
63
+ }
64
+ >
78
65
  <TouchableOpacity onPress={() => setOpen(true)}>
79
66
  <TextInput
80
67
  label={label}
@@ -84,6 +71,7 @@ function MultiSelect<T>({
84
71
  error={error}
85
72
  editable={editable}
86
73
  disabled={disabled}
74
+ loading={inputProps?.loading}
87
75
  numberOfLines={numberOfLines}
88
76
  pointerEvents="none"
89
77
  style={style}
@@ -124,9 +112,11 @@ function MultiSelect<T>({
124
112
  </StyledSearchBar>
125
113
  )}
126
114
  <OptionList
115
+ onQueryChange={onQueryChange}
127
116
  onEndReached={onEndReached}
128
117
  loading={loading}
129
- options={options}
118
+ sections={sections}
119
+ renderOption={renderOption}
130
120
  value={selectingValue}
131
121
  onPress={setSelectingValue}
132
122
  />
@@ -1,14 +1,30 @@
1
- import React from 'react';
1
+ import React, { ReactElement } from 'react';
2
+ import { useTheme } from '../../../theme';
2
3
  import List from '../../List';
3
4
 
4
5
  const Option = ({
5
6
  text,
7
+ disabled = false,
6
8
  selected,
7
9
  onPress,
8
10
  }: {
9
- text: string;
11
+ text: string | ReactElement;
12
+ disabled?: boolean;
10
13
  selected: boolean;
11
14
  onPress: () => void;
12
- }) => <List.BasicItem selected={selected} onPress={onPress} title={text} />;
15
+ }) => {
16
+ const theme = useTheme();
17
+ return (
18
+ <List.BasicItem
19
+ selected={selected}
20
+ disabled={disabled}
21
+ onPress={onPress}
22
+ title={text}
23
+ style={{
24
+ marginHorizontal: theme.__hd__.select.space.optionHorizontalMargin,
25
+ }}
26
+ />
27
+ );
28
+ };
13
29
 
14
30
  export default Option;
@@ -1,60 +1,68 @@
1
1
  import React from 'react';
2
+ import { SectionListRenderItemInfo } from 'react-native';
2
3
  import { SingleSelectProps } from '.';
3
-
4
- import StyledOptionList, { RenderItemProps } from '../StyledOptionList';
4
+ import { getScrollParams } from '../helpers';
5
+ import StyledOptionList from '../StyledOptionList';
6
+ import { OptionType, SectionData, SectionType } from '../types';
5
7
  import Option from './Option';
6
8
 
7
- interface OptionListProps<T> extends SingleSelectProps<T> {
8
- /**
9
- * event handler for select
10
- */
11
- onPress: (value: T | null) => void;
12
- }
9
+ type OptionListProps<V, T extends OptionType<V>> = Pick<
10
+ SingleSelectProps<V, T>,
11
+ | 'keyExtractor'
12
+ | 'loading'
13
+ | 'onEndReached'
14
+ | 'onQueryChange'
15
+ | 'value'
16
+ | 'renderOption'
17
+ > & {
18
+ onPress: (value: V | null) => void;
19
+ sections: SectionData<V, T>[];
20
+ };
13
21
 
14
- const OptionList = <T,>({
22
+ const OptionList = <V, T extends OptionType<V>>({
15
23
  keyExtractor,
16
24
  loading,
17
25
  onEndReached,
18
26
  onPress,
19
27
  onQueryChange,
20
- options,
28
+ sections,
29
+ renderOption,
21
30
  value,
22
- }: Pick<
23
- OptionListProps<T>,
24
- | 'keyExtractor'
25
- | 'loading'
26
- | 'onEndReached'
27
- | 'onPress'
28
- | 'onQueryChange'
29
- | 'options'
30
- | 'value'
31
- >) => {
32
- const rawScrollIndex = options.findIndex(option => option.value === value);
33
- const scrollIndex = rawScrollIndex - 2 >= 0 ? rawScrollIndex - 2 : 0;
31
+ }: OptionListProps<V, T>) => {
32
+ const scrollParams = getScrollParams(value, sections);
34
33
 
35
- const RenderItem = React.memo(({ item }: RenderItemProps<T>) => (
36
- <Option
37
- selected={value === item.value}
38
- text={item.text}
39
- onPress={() => {
40
- if (value === item.value) {
41
- onPress(null);
42
- } else {
43
- onPress(item.value);
44
- }
45
- }}
46
- />
47
- ));
34
+ const renderItem = (info: SectionListRenderItemInfo<T, SectionType>) => {
35
+ const { item } = info;
36
+ const selected = item.value === value;
37
+ const onItemPress = () => {
38
+ if (value === item.value) {
39
+ onPress(null);
40
+ } else {
41
+ onPress(item.value);
42
+ }
43
+ };
44
+
45
+ return renderOption ? (
46
+ renderOption({ ...info, selected, onPress: onItemPress })
47
+ ) : (
48
+ <Option
49
+ selected={selected}
50
+ text={item.text}
51
+ disabled={item.disabled}
52
+ onPress={onItemPress}
53
+ />
54
+ );
55
+ };
48
56
 
49
57
  return (
50
- <StyledOptionList<T>
58
+ <StyledOptionList
51
59
  keyExtractor={keyExtractor}
52
60
  loading={loading}
53
61
  onEndReached={onEndReached}
54
62
  onQueryChange={onQueryChange}
55
- options={options}
56
- RenderItem={RenderItem}
57
- scrollIndex={scrollIndex}
63
+ sections={sections}
64
+ renderItem={renderItem}
65
+ scrollParams={scrollParams}
58
66
  />
59
67
  );
60
68
  };
@@ -3,39 +3,50 @@ import { fireEvent } from '@testing-library/react-native';
3
3
  import OptionList from '../OptionList';
4
4
  import renderWithTheme from '../../../../testHelpers/renderWithTheme';
5
5
 
6
- const mockOptions = [
7
- { text: 'A', value: 'a' },
8
- { text: 'B', value: 'b' },
9
- { text: 'C', value: 'c' },
6
+ const sections = [
7
+ { category: 'A', data: [{ text: 'A1', value: 'a1' }] },
8
+ {
9
+ category: 'B',
10
+ data: [
11
+ { text: 'B1', value: 'b1' },
12
+ { text: 'B2', value: 'b2' },
13
+ ],
14
+ },
10
15
  ];
11
16
 
12
17
  describe('OptionList', () => {
13
18
  it('renders correctly', () => {
14
19
  const pressFn = jest.fn();
15
- const { toJSON } = renderWithTheme(
16
- <OptionList value="a" options={mockOptions} onPress={pressFn} />
20
+ const { toJSON, getByText } = renderWithTheme(
21
+ <OptionList value="a1" sections={sections} onPress={pressFn} />
17
22
  );
23
+
24
+ expect(getByText('A')).toBeTruthy();
25
+ expect(getByText('A1')).toBeTruthy();
26
+ expect(getByText('B')).toBeTruthy();
27
+ expect(getByText('B1')).toBeTruthy();
28
+ expect(getByText('B2')).toBeTruthy();
18
29
  expect(toJSON()).toMatchSnapshot();
19
30
  });
20
31
 
21
32
  it('trigger onPress correctly on select new value', () => {
22
33
  const pressFn = jest.fn();
23
34
  const { toJSON, getByText } = renderWithTheme(
24
- <OptionList value="a" options={mockOptions} onPress={pressFn} />
35
+ <OptionList value="a1" sections={sections} onPress={pressFn} />
25
36
  );
26
37
  expect(toJSON()).toMatchSnapshot();
27
- fireEvent.press(getByText('B'));
38
+ fireEvent.press(getByText('B1'));
28
39
  expect(pressFn).toBeCalledTimes(1);
29
- expect(pressFn).toHaveBeenCalledWith('b');
40
+ expect(pressFn).toHaveBeenCalledWith('b1');
30
41
  });
31
42
 
32
43
  it('trigger onPress correctly on unselect current value', () => {
33
44
  const pressFn = jest.fn();
34
45
  const { toJSON, getByText } = renderWithTheme(
35
- <OptionList value="a" options={mockOptions} onPress={pressFn} />
46
+ <OptionList value="a1" sections={sections} onPress={pressFn} />
36
47
  );
37
48
  expect(toJSON()).toMatchSnapshot();
38
- fireEvent.press(getByText('A'));
49
+ fireEvent.press(getByText('A1'));
39
50
  expect(pressFn).toBeCalledTimes(1);
40
51
  expect(pressFn).toHaveBeenCalledWith(null);
41
52
  });
@@ -43,7 +54,7 @@ describe('OptionList', () => {
43
54
  it('render isLoading correctly', () => {
44
55
  const pressFn = jest.fn();
45
56
  const { toJSON } = renderWithTheme(
46
- <OptionList value="a" options={mockOptions} onPress={pressFn} loading />
57
+ <OptionList value="a1" sections={sections} onPress={pressFn} loading />
47
58
  );
48
59
  expect(toJSON()).toMatchSnapshot();
49
60
  });
@@ -20,12 +20,14 @@ exports[`Option renders correctly 1`] = `
20
20
  Array [
21
21
  Object {
22
22
  "alignItems": "center",
23
- "backgroundColor": "#f1e9fb",
23
+ "backgroundColor": "#f3e6f6",
24
24
  "flexDirection": "row",
25
25
  "opacity": 1,
26
26
  "padding": 16,
27
27
  },
28
- undefined,
28
+ Object {
29
+ "marginHorizontal": 12,
30
+ },
29
31
  ]
30
32
  }
31
33
  >
@@ -43,7 +45,7 @@ exports[`Option renders correctly 1`] = `
43
45
  style={
44
46
  Array [
45
47
  Object {
46
- "color": "#292a2b",
48
+ "color": "#001f23",
47
49
  "fontFamily": "BeVietnamPro-Regular",
48
50
  "fontSize": 16,
49
51
  "letterSpacing": 0.48,