@hero-design/rn 7.20.1 → 7.21.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 (92) hide show
  1. package/.eslintrc.json +1 -0
  2. package/.turbo/turbo-build.log +2 -2
  3. package/es/index.js +370 -237
  4. package/lib/index.js +370 -234
  5. package/package.json +4 -2
  6. package/rollup.config.js +1 -0
  7. package/src/components/BottomSheet/index.tsx +6 -1
  8. package/src/components/Checkbox/__tests__/__snapshots__/StyledCheckbox.spec.tsx.snap +4 -4
  9. package/src/components/Checkbox/__tests__/__snapshots__/index.spec.tsx.snap +13 -13
  10. package/src/components/Empty/StyledEmpty.tsx +1 -9
  11. package/src/components/Empty/__tests__/__snapshots__/index.spec.tsx.snap +58 -5
  12. package/src/components/Empty/__tests__/index.spec.tsx +13 -0
  13. package/src/components/Empty/index.tsx +38 -18
  14. package/src/components/Image/__tests__/__snapshots__/index.spec.tsx.snap +81 -0
  15. package/src/components/Image/__tests__/index.spec.tsx +29 -0
  16. package/src/components/Image/index.tsx +46 -0
  17. package/src/components/List/__tests__/__snapshots__/ListItem.spec.tsx.snap +5 -5
  18. package/src/components/Progress/__tests__/__snapshots__/index.spec.js.snap +60 -60
  19. package/src/components/RichTextEditor/__tests__/__snapshots__/EditorToolbar.spec.tsx.snap +2 -2
  20. package/src/components/RichTextEditor/__tests__/__snapshots__/RichTextEditor.spec.tsx.snap +2 -2
  21. package/src/components/Select/MultiSelect/OptionList.tsx +4 -6
  22. package/src/components/Select/MultiSelect/__tests__/index.spec.tsx +21 -0
  23. package/src/components/Select/MultiSelect/index.tsx +33 -3
  24. package/src/components/Select/SingleSelect/OptionList.tsx +4 -5
  25. package/src/components/Select/SingleSelect/__tests__/index.spec.tsx +16 -0
  26. package/src/components/Select/SingleSelect/index.tsx +34 -4
  27. package/src/components/Select/StyledOptionList.tsx +3 -9
  28. package/src/components/Slider/__tests__/__snapshots__/index.spec.tsx.snap +43 -0
  29. package/src/components/Slider/__tests__/index.spec.tsx +33 -0
  30. package/src/components/Slider/index.tsx +89 -0
  31. package/src/components/Switch/StyledSwitch.tsx +4 -4
  32. package/src/components/Switch/__tests__/__snapshots__/StyledSwitch.spec.tsx.snap +10 -10
  33. package/src/components/Switch/__tests__/__snapshots__/index.spec.tsx.snap +8 -8
  34. package/src/components/Switch/index.tsx +5 -4
  35. package/src/components/TextInput/index.tsx +43 -37
  36. package/src/index.ts +4 -0
  37. package/src/theme/__tests__/__snapshots__/index.spec.ts.snap +56 -11
  38. package/src/theme/components/alert.ts +1 -2
  39. package/src/theme/components/avatar.ts +8 -8
  40. package/src/theme/components/badge.ts +4 -4
  41. package/src/theme/components/bottomNavigation.ts +1 -1
  42. package/src/theme/components/bottomSheet.ts +2 -3
  43. package/src/theme/components/calendar.ts +9 -7
  44. package/src/theme/components/card.ts +1 -1
  45. package/src/theme/components/checkbox.ts +2 -5
  46. package/src/theme/components/datePicker.ts +3 -3
  47. package/src/theme/components/drawer.ts +2 -3
  48. package/src/theme/components/empty.ts +3 -8
  49. package/src/theme/components/fab.ts +2 -2
  50. package/src/theme/components/image.ts +12 -0
  51. package/src/theme/components/pinInput.ts +3 -3
  52. package/src/theme/components/progress.ts +2 -3
  53. package/src/theme/components/radio.ts +7 -3
  54. package/src/theme/components/richTextEditor.ts +4 -4
  55. package/src/theme/components/slider.ts +13 -0
  56. package/src/theme/components/switch.ts +16 -1
  57. package/src/theme/components/tabs.ts +1 -1
  58. package/src/theme/components/timePicker.ts +3 -3
  59. package/src/theme/components/toast.ts +1 -2
  60. package/src/theme/getTheme.ts +9 -2
  61. package/src/theme/global/colors/swag.ts +2 -0
  62. package/src/theme/global/colors/types.ts +2 -0
  63. package/src/theme/global/index.ts +3 -0
  64. package/src/theme/global/scale.ts +3 -0
  65. package/src/theme/global/sizes.ts +29 -0
  66. package/testUtils/setup.tsx +14 -0
  67. package/types/components/BottomSheet/index.d.ts +5 -1
  68. package/types/components/Empty/StyledEmpty.d.ts +1 -7
  69. package/types/components/Empty/index.d.ts +8 -2
  70. package/types/components/Image/__tests__/index.spec.d.ts +1 -0
  71. package/types/components/Image/index.d.ts +17 -0
  72. package/types/components/Select/MultiSelect/OptionList.d.ts +5 -2
  73. package/types/components/Select/MultiSelect/index.d.ts +7 -1
  74. package/types/components/Select/SingleSelect/OptionList.d.ts +5 -2
  75. package/types/components/Select/SingleSelect/index.d.ts +8 -2
  76. package/types/components/Select/StyledOptionList.d.ts +4 -3
  77. package/types/components/Select/index.d.ts +1 -1
  78. package/types/components/Slider/__tests__/index.spec.d.ts +1 -0
  79. package/types/components/Slider/index.d.ts +52 -0
  80. package/types/components/TextInput/index.d.ts +2 -1
  81. package/types/index.d.ts +3 -1
  82. package/types/theme/components/datePicker.d.ts +2 -1
  83. package/types/theme/components/empty.d.ts +2 -5
  84. package/types/theme/components/image.d.ts +8 -0
  85. package/types/theme/components/slider.d.ts +9 -0
  86. package/types/theme/components/switch.d.ts +14 -1
  87. package/types/theme/components/timePicker.d.ts +2 -1
  88. package/types/theme/getTheme.d.ts +4 -0
  89. package/types/theme/global/colors/types.d.ts +2 -0
  90. package/types/theme/global/index.d.ts +3 -0
  91. package/types/theme/global/scale.d.ts +1 -0
  92. package/types/theme/global/sizes.d.ts +14 -0
@@ -96,9 +96,9 @@ exports[`Progress.Circle renders correctly 1`] = `
96
96
  style={
97
97
  Array [
98
98
  Object {
99
- "height": 76,
99
+ "height": 72,
100
100
  "overflow": "hidden",
101
- "width": 38,
101
+ "width": 36,
102
102
  },
103
103
  undefined,
104
104
  ]
@@ -110,8 +110,8 @@ exports[`Progress.Circle renders correctly 1`] = `
110
110
  Object {
111
111
  "backgroundColor": "#8505a2",
112
112
  "borderRadius": 999,
113
- "height": 76,
114
- "width": 76,
113
+ "height": 72,
114
+ "width": 72,
115
115
  },
116
116
  undefined,
117
117
  ]
@@ -131,13 +131,13 @@ exports[`Progress.Circle renders correctly 1`] = `
131
131
  "top": 0,
132
132
  "transform": Array [
133
133
  Object {
134
- "translateX": 19,
134
+ "translateX": 18,
135
135
  },
136
136
  Object {
137
137
  "rotate": "0deg",
138
138
  },
139
139
  Object {
140
- "translateX": -19,
140
+ "translateX": -18,
141
141
  },
142
142
  ],
143
143
  }
@@ -147,9 +147,9 @@ exports[`Progress.Circle renders correctly 1`] = `
147
147
  style={
148
148
  Array [
149
149
  Object {
150
- "height": 76,
150
+ "height": 72,
151
151
  "overflow": "hidden",
152
- "width": 38,
152
+ "width": 36,
153
153
  },
154
154
  undefined,
155
155
  ]
@@ -161,8 +161,8 @@ exports[`Progress.Circle renders correctly 1`] = `
161
161
  Object {
162
162
  "backgroundColor": "#e8e9ea",
163
163
  "borderRadius": 999,
164
- "height": 76,
165
- "width": 76,
164
+ "height": 72,
165
+ "width": 72,
166
166
  },
167
167
  undefined,
168
168
  ]
@@ -188,9 +188,9 @@ exports[`Progress.Circle renders correctly 1`] = `
188
188
  style={
189
189
  Array [
190
190
  Object {
191
- "height": 76,
191
+ "height": 72,
192
192
  "overflow": "hidden",
193
- "width": 38,
193
+ "width": 36,
194
194
  },
195
195
  undefined,
196
196
  ]
@@ -202,8 +202,8 @@ exports[`Progress.Circle renders correctly 1`] = `
202
202
  Object {
203
203
  "backgroundColor": "#8505a2",
204
204
  "borderRadius": 999,
205
- "height": 76,
206
- "width": 76,
205
+ "height": 72,
206
+ "width": 72,
207
207
  },
208
208
  undefined,
209
209
  ]
@@ -224,13 +224,13 @@ exports[`Progress.Circle renders correctly 1`] = `
224
224
  "top": 0,
225
225
  "transform": Array [
226
226
  Object {
227
- "translateX": 19,
227
+ "translateX": 18,
228
228
  },
229
229
  Object {
230
230
  "rotate": "0deg",
231
231
  },
232
232
  Object {
233
- "translateX": -19,
233
+ "translateX": -18,
234
234
  },
235
235
  ],
236
236
  }
@@ -240,9 +240,9 @@ exports[`Progress.Circle renders correctly 1`] = `
240
240
  style={
241
241
  Array [
242
242
  Object {
243
- "height": 76,
243
+ "height": 72,
244
244
  "overflow": "hidden",
245
- "width": 38,
245
+ "width": 36,
246
246
  },
247
247
  undefined,
248
248
  ]
@@ -254,8 +254,8 @@ exports[`Progress.Circle renders correctly 1`] = `
254
254
  Object {
255
255
  "backgroundColor": "#e8e9ea",
256
256
  "borderRadius": 999,
257
- "height": 76,
258
- "width": 76,
257
+ "height": 72,
258
+ "width": 72,
259
259
  },
260
260
  undefined,
261
261
  ]
@@ -270,11 +270,11 @@ exports[`Progress.Circle renders correctly 1`] = `
270
270
  Object {
271
271
  "backgroundColor": "#8505a2",
272
272
  "borderRadius": 999,
273
- "height": 5.7,
274
- "left": 35.15,
273
+ "height": 5.3999999999999995,
274
+ "left": 33.3,
275
275
  "position": "absolute",
276
276
  "top": 0,
277
- "width": 5.7,
277
+ "width": 5.3999999999999995,
278
278
  "zIndex": 2,
279
279
  },
280
280
  undefined,
@@ -307,11 +307,11 @@ exports[`Progress.Circle renders correctly 1`] = `
307
307
  Object {
308
308
  "backgroundColor": "#8505a2",
309
309
  "borderRadius": 999,
310
- "height": 5.7,
311
- "left": 35.15,
310
+ "height": 5.3999999999999995,
311
+ "left": 33.3,
312
312
  "position": "absolute",
313
313
  "top": 0,
314
- "width": 5.7,
314
+ "width": 5.3999999999999995,
315
315
  "zIndex": 2,
316
316
  },
317
317
  undefined,
@@ -327,12 +327,12 @@ exports[`Progress.Circle renders correctly 1`] = `
327
327
  "alignItems": "center",
328
328
  "backgroundColor": "#ffffff",
329
329
  "borderRadius": 999,
330
- "height": 64.6,
330
+ "height": 61.199999999999996,
331
331
  "justifyContent": "center",
332
- "left": 5.7,
332
+ "left": 5.3999999999999995,
333
333
  "position": "absolute",
334
- "top": 5.7,
335
- "width": 64.6,
334
+ "top": 5.3999999999999995,
335
+ "width": 61.199999999999996,
336
336
  "zIndex": 3,
337
337
  },
338
338
  undefined,
@@ -383,9 +383,9 @@ exports[`Progress.Circle renders correctly with intent 1`] = `
383
383
  style={
384
384
  Array [
385
385
  Object {
386
- "height": 76,
386
+ "height": 72,
387
387
  "overflow": "hidden",
388
- "width": 38,
388
+ "width": 36,
389
389
  },
390
390
  undefined,
391
391
  ]
@@ -397,8 +397,8 @@ exports[`Progress.Circle renders correctly with intent 1`] = `
397
397
  Object {
398
398
  "backgroundColor": "#5ace7d",
399
399
  "borderRadius": 999,
400
- "height": 76,
401
- "width": 76,
400
+ "height": 72,
401
+ "width": 72,
402
402
  },
403
403
  undefined,
404
404
  ]
@@ -418,13 +418,13 @@ exports[`Progress.Circle renders correctly with intent 1`] = `
418
418
  "top": 0,
419
419
  "transform": Array [
420
420
  Object {
421
- "translateX": 19,
421
+ "translateX": 18,
422
422
  },
423
423
  Object {
424
424
  "rotate": "0deg",
425
425
  },
426
426
  Object {
427
- "translateX": -19,
427
+ "translateX": -18,
428
428
  },
429
429
  ],
430
430
  }
@@ -434,9 +434,9 @@ exports[`Progress.Circle renders correctly with intent 1`] = `
434
434
  style={
435
435
  Array [
436
436
  Object {
437
- "height": 76,
437
+ "height": 72,
438
438
  "overflow": "hidden",
439
- "width": 38,
439
+ "width": 36,
440
440
  },
441
441
  undefined,
442
442
  ]
@@ -448,8 +448,8 @@ exports[`Progress.Circle renders correctly with intent 1`] = `
448
448
  Object {
449
449
  "backgroundColor": "#e8e9ea",
450
450
  "borderRadius": 999,
451
- "height": 76,
452
- "width": 76,
451
+ "height": 72,
452
+ "width": 72,
453
453
  },
454
454
  undefined,
455
455
  ]
@@ -475,9 +475,9 @@ exports[`Progress.Circle renders correctly with intent 1`] = `
475
475
  style={
476
476
  Array [
477
477
  Object {
478
- "height": 76,
478
+ "height": 72,
479
479
  "overflow": "hidden",
480
- "width": 38,
480
+ "width": 36,
481
481
  },
482
482
  undefined,
483
483
  ]
@@ -489,8 +489,8 @@ exports[`Progress.Circle renders correctly with intent 1`] = `
489
489
  Object {
490
490
  "backgroundColor": "#5ace7d",
491
491
  "borderRadius": 999,
492
- "height": 76,
493
- "width": 76,
492
+ "height": 72,
493
+ "width": 72,
494
494
  },
495
495
  undefined,
496
496
  ]
@@ -511,13 +511,13 @@ exports[`Progress.Circle renders correctly with intent 1`] = `
511
511
  "top": 0,
512
512
  "transform": Array [
513
513
  Object {
514
- "translateX": 19,
514
+ "translateX": 18,
515
515
  },
516
516
  Object {
517
517
  "rotate": "0deg",
518
518
  },
519
519
  Object {
520
- "translateX": -19,
520
+ "translateX": -18,
521
521
  },
522
522
  ],
523
523
  }
@@ -527,9 +527,9 @@ exports[`Progress.Circle renders correctly with intent 1`] = `
527
527
  style={
528
528
  Array [
529
529
  Object {
530
- "height": 76,
530
+ "height": 72,
531
531
  "overflow": "hidden",
532
- "width": 38,
532
+ "width": 36,
533
533
  },
534
534
  undefined,
535
535
  ]
@@ -541,8 +541,8 @@ exports[`Progress.Circle renders correctly with intent 1`] = `
541
541
  Object {
542
542
  "backgroundColor": "#e8e9ea",
543
543
  "borderRadius": 999,
544
- "height": 76,
545
- "width": 76,
544
+ "height": 72,
545
+ "width": 72,
546
546
  },
547
547
  undefined,
548
548
  ]
@@ -557,11 +557,11 @@ exports[`Progress.Circle renders correctly with intent 1`] = `
557
557
  Object {
558
558
  "backgroundColor": "#5ace7d",
559
559
  "borderRadius": 999,
560
- "height": 5.7,
561
- "left": 35.15,
560
+ "height": 5.3999999999999995,
561
+ "left": 33.3,
562
562
  "position": "absolute",
563
563
  "top": 0,
564
- "width": 5.7,
564
+ "width": 5.3999999999999995,
565
565
  "zIndex": 2,
566
566
  },
567
567
  undefined,
@@ -594,11 +594,11 @@ exports[`Progress.Circle renders correctly with intent 1`] = `
594
594
  Object {
595
595
  "backgroundColor": "#5ace7d",
596
596
  "borderRadius": 999,
597
- "height": 5.7,
598
- "left": 35.15,
597
+ "height": 5.3999999999999995,
598
+ "left": 33.3,
599
599
  "position": "absolute",
600
600
  "top": 0,
601
- "width": 5.7,
601
+ "width": 5.3999999999999995,
602
602
  "zIndex": 2,
603
603
  },
604
604
  undefined,
@@ -614,12 +614,12 @@ exports[`Progress.Circle renders correctly with intent 1`] = `
614
614
  "alignItems": "center",
615
615
  "backgroundColor": "#ffffff",
616
616
  "borderRadius": 999,
617
- "height": 64.6,
617
+ "height": 61.199999999999996,
618
618
  "justifyContent": "center",
619
- "left": 5.7,
619
+ "left": 5.3999999999999995,
620
620
  "position": "absolute",
621
- "top": 5.7,
622
- "width": 64.6,
621
+ "top": 5.3999999999999995,
622
+ "width": 61.199999999999996,
623
623
  "zIndex": 3,
624
624
  },
625
625
  undefined,
@@ -143,7 +143,7 @@ exports[`EditorToolbar when the editor is focused should render toolbar 1`] = `
143
143
  "flexDirection": "row",
144
144
  "height": 16,
145
145
  "marginHorizontal": 8,
146
- "width": 1,
146
+ "width": 2,
147
147
  },
148
148
  undefined,
149
149
  ]
@@ -236,7 +236,7 @@ exports[`EditorToolbar when the editor is focused should render toolbar 1`] = `
236
236
  "flexDirection": "row",
237
237
  "height": 16,
238
238
  "marginHorizontal": 8,
239
- "width": 1,
239
+ "width": 2,
240
240
  },
241
241
  undefined,
242
242
  ]
@@ -165,7 +165,7 @@ exports[`RichTextEditor onMessage recevied event editor-layout should update hei
165
165
  "fontSize": 14,
166
166
  "height": 480,
167
167
  "marginHorizontal": 8,
168
- "minHeight": 21,
168
+ "minHeight": 24,
169
169
  "textAlignVertical": "center",
170
170
  },
171
171
  Object {
@@ -424,7 +424,7 @@ exports[`RichTextEditor should render correctly 1`] = `
424
424
  "fontSize": 14,
425
425
  "height": undefined,
426
426
  "marginHorizontal": 8,
427
- "minHeight": 21,
427
+ "minHeight": 24,
428
428
  "textAlignVertical": "center",
429
429
  },
430
430
  Object {
@@ -1,6 +1,5 @@
1
1
  import React from 'react';
2
- import type { SectionListRenderItemInfo } from 'react-native';
3
- import { getScrollParams } from '../helpers';
2
+ import type { SectionListRenderItemInfo, SectionList } from 'react-native';
4
3
  import StyledOptionList from '../StyledOptionList';
5
4
  import Option from './Option';
6
5
  import type { MultiSelectProps } from '.';
@@ -17,6 +16,7 @@ type OptionListProps<V, T extends OptionType<V>> = Pick<
17
16
  > & {
18
17
  onPress: (value: V[]) => void;
19
18
  sections: SectionData<V, T>[];
19
+ sectionListRef?: React.RefObject<SectionList<T, SectionType>>;
20
20
  };
21
21
 
22
22
  const OptionList = <V, T extends OptionType<V>>({
@@ -28,10 +28,8 @@ const OptionList = <V, T extends OptionType<V>>({
28
28
  sections,
29
29
  renderOption,
30
30
  value,
31
+ sectionListRef,
31
32
  }: OptionListProps<V, T>) => {
32
- const firstValue = value?.[0];
33
- const scrollParams = getScrollParams(firstValue, sections);
34
-
35
33
  const renderItem = (info: SectionListRenderItemInfo<T, SectionType>) => {
36
34
  const { item } = info;
37
35
  const selected = value.includes(info.item.value);
@@ -63,7 +61,7 @@ const OptionList = <V, T extends OptionType<V>>({
63
61
  onQueryChange={onQueryChange}
64
62
  sections={sections}
65
63
  renderItem={renderItem}
66
- scrollParams={scrollParams}
64
+ sectionListRef={sectionListRef}
67
65
  />
68
66
  );
69
67
  };
@@ -174,6 +174,27 @@ describe('rendering', () => {
174
174
  expect(getByText('Josh')).toBeTruthy();
175
175
  expect(getByText('Junior Developer')).toBeTruthy();
176
176
  });
177
+
178
+ it('allows custom selected value', () => {
179
+ const { getByText } = renderWithTheme(
180
+ <MultiSelect<string, CustomOptionType>
181
+ label="Choose collaborators"
182
+ footerLabel="Confirm"
183
+ options={collaboratorSections}
184
+ value={['daniel', 'daemon']}
185
+ onConfirm={jest.fn()}
186
+ renderSelectedValue={(selectedValue, _inputProps) => (
187
+ <>
188
+ {selectedValue.map(value => (
189
+ <Typography.Text>Custom {value}</Typography.Text>
190
+ ))}
191
+ </>
192
+ )}
193
+ />
194
+ );
195
+ expect(getByText('Custom daniel')).toBeTruthy();
196
+ expect(getByText('Custom daemon')).toBeTruthy();
197
+ });
177
198
  });
178
199
 
179
200
  describe('behavior', () => {
@@ -1,12 +1,21 @@
1
- import React, { useState } from 'react';
1
+ import React, { useState, useRef } from 'react';
2
2
  import { TouchableOpacity, View } from 'react-native';
3
+ import type {
4
+ SectionList,
5
+ TextInputProps as NativeTextInputProps,
6
+ } from 'react-native';
3
7
  import BottomSheet from '../../BottomSheet';
4
8
  import Footer from '../Footer';
5
9
  import OptionList from './OptionList';
6
10
  import TextInput from '../../TextInput';
7
11
  import { StyledSearchBar } from '../StyledSelect';
8
- import { toFlatOptions, toSections, useKeyboard } from '../helpers';
9
- import type { OptionType, SelectProps } from '../types';
12
+ import {
13
+ getScrollParams,
14
+ toFlatOptions,
15
+ toSections,
16
+ useKeyboard,
17
+ } from '../helpers';
18
+ import type { OptionType, SectionType, SelectProps } from '../types';
10
19
 
11
20
  export interface MultiSelectProps<V, T extends OptionType<V> = OptionType<V>>
12
21
  extends SelectProps<V, T> {
@@ -22,6 +31,13 @@ export interface MultiSelectProps<V, T extends OptionType<V> = OptionType<V>>
22
31
  * Footer label.
23
32
  */
24
33
  footerLabel: string;
34
+ /**
35
+ * Customise the selected value rendering.
36
+ */
37
+ renderSelectedValue?: (
38
+ selectedValue: V[],
39
+ inputProps: NativeTextInputProps
40
+ ) => React.ReactNode;
25
41
  }
26
42
 
27
43
  function MultiSelect<V, T extends OptionType<V>>({
@@ -35,6 +51,7 @@ function MultiSelect<V, T extends OptionType<V>>({
35
51
  onQueryChange,
36
52
  options,
37
53
  renderOption,
54
+ renderSelectedValue,
38
55
  query,
39
56
  error,
40
57
  editable = true,
@@ -47,6 +64,7 @@ function MultiSelect<V, T extends OptionType<V>>({
47
64
  const { isKeyboardVisible, keyboardHeight } = useKeyboard();
48
65
  const [open, setOpen] = useState(false);
49
66
  const [selectingValue, setSelectingValue] = useState(value);
67
+ const sectionListRef = useRef<SectionList<T, SectionType>>(null);
50
68
  const sections = toSections(options);
51
69
  const flatOptions = toFlatOptions(options);
52
70
  const displayedValue = flatOptions
@@ -79,6 +97,11 @@ function MultiSelect<V, T extends OptionType<V>>({
79
97
  pointerEvents="none"
80
98
  style={style}
81
99
  testID={testID}
100
+ renderInputValue={
101
+ renderSelectedValue !== undefined
102
+ ? props => renderSelectedValue(value, props)
103
+ : undefined
104
+ }
82
105
  />
83
106
  </View>
84
107
  </TouchableOpacity>
@@ -100,6 +123,12 @@ function MultiSelect<V, T extends OptionType<V>>({
100
123
  }}
101
124
  />
102
125
  }
126
+ onAnimationEnd={() => {
127
+ if (open === true) {
128
+ const scrollParams = getScrollParams(value?.[0], sections);
129
+ sectionListRef.current?.scrollToLocation(scrollParams);
130
+ }
131
+ }}
103
132
  >
104
133
  {onQueryChange && (
105
134
  <StyledSearchBar>
@@ -120,6 +149,7 @@ function MultiSelect<V, T extends OptionType<V>>({
120
149
  renderOption={renderOption}
121
150
  value={selectingValue}
122
151
  onPress={setSelectingValue}
152
+ sectionListRef={sectionListRef}
123
153
  />
124
154
  </BottomSheet>
125
155
  </>
@@ -1,6 +1,5 @@
1
1
  import React from 'react';
2
- import type { SectionListRenderItemInfo } from 'react-native';
3
- import { getScrollParams } from '../helpers';
2
+ import type { SectionListRenderItemInfo, SectionList } from 'react-native';
4
3
  import StyledOptionList from '../StyledOptionList';
5
4
  import Option from './Option';
6
5
  import type { SingleSelectProps } from '.';
@@ -17,6 +16,7 @@ type OptionListProps<V, T extends OptionType<V>> = Pick<
17
16
  > & {
18
17
  onPress: (value: V | null) => void;
19
18
  sections: SectionData<V, T>[];
19
+ sectionListRef?: React.RefObject<SectionList<T, SectionType>>;
20
20
  };
21
21
 
22
22
  const OptionList = <V, T extends OptionType<V>>({
@@ -28,9 +28,8 @@ const OptionList = <V, T extends OptionType<V>>({
28
28
  sections,
29
29
  renderOption,
30
30
  value,
31
+ sectionListRef,
31
32
  }: OptionListProps<V, T>) => {
32
- const scrollParams = getScrollParams(value, sections);
33
-
34
33
  const renderItem = (info: SectionListRenderItemInfo<T, SectionType>) => {
35
34
  const { item } = info;
36
35
  const selected = item.value === value;
@@ -62,7 +61,7 @@ const OptionList = <V, T extends OptionType<V>>({
62
61
  onQueryChange={onQueryChange}
63
62
  sections={sections}
64
63
  renderItem={renderItem}
65
- scrollParams={scrollParams}
64
+ sectionListRef={sectionListRef}
66
65
  />
67
66
  );
68
67
  };
@@ -166,6 +166,22 @@ describe('rendering', () => {
166
166
  expect(getByText('Josh')).toBeTruthy();
167
167
  expect(getByText('Junior Developer')).toBeTruthy();
168
168
  });
169
+
170
+ it('allows custom selected value', () => {
171
+ const { getByText } = renderWithTheme(
172
+ <SingleSelect<string, CustomOptionType>
173
+ label="Choose collaborators"
174
+ options={collaboratorSections}
175
+ renderOption={renderSingleOption}
176
+ value="daniel"
177
+ onConfirm={jest.fn()}
178
+ renderSelectedValue={(selectedValue, _inputProps) => (
179
+ <Typography.Text>Custom {selectedValue}</Typography.Text>
180
+ )}
181
+ />
182
+ );
183
+ expect(getByText('Custom daniel')).toBeTruthy();
184
+ });
169
185
  });
170
186
 
171
187
  describe('behavior', () => {
@@ -1,11 +1,20 @@
1
- import React, { useState } from 'react';
1
+ import React, { useState, useRef } from 'react';
2
2
  import { TouchableOpacity, View } from 'react-native';
3
+ import type {
4
+ SectionList,
5
+ TextInputProps as NativeTextInputProps,
6
+ } from 'react-native';
3
7
  import BottomSheet from '../../BottomSheet';
4
8
  import OptionList from './OptionList';
5
9
  import TextInput from '../../TextInput';
6
10
  import { StyledSearchBar } from '../StyledSelect';
7
- import { toFlatOptions, toSections, useKeyboard } from '../helpers';
8
- import type { OptionType, SelectProps } from '../types';
11
+ import {
12
+ getScrollParams,
13
+ toFlatOptions,
14
+ toSections,
15
+ useKeyboard,
16
+ } from '../helpers';
17
+ import type { OptionType, SectionType, SelectProps } from '../types';
9
18
 
10
19
  export interface SingleSelectProps<V, T extends OptionType<V> = OptionType<V>>
11
20
  extends SelectProps<V, T> {
@@ -14,9 +23,16 @@ export interface SingleSelectProps<V, T extends OptionType<V> = OptionType<V>>
14
23
  */
15
24
  value: V | null;
16
25
  /**
17
- * on select event handler
26
+ * On select event handler
18
27
  */
19
28
  onConfirm: (value: V | null) => void;
29
+ /**
30
+ * Customise the selected value rendering.
31
+ */
32
+ renderSelectedValue?: (
33
+ selectedValue: V | null,
34
+ inputProps: NativeTextInputProps
35
+ ) => React.ReactNode;
20
36
  }
21
37
 
22
38
  const SingleSelect = <V, T extends OptionType<V>>({
@@ -29,6 +45,7 @@ const SingleSelect = <V, T extends OptionType<V>>({
29
45
  onQueryChange,
30
46
  options,
31
47
  renderOption,
48
+ renderSelectedValue,
32
49
  query,
33
50
  error,
34
51
  editable = true,
@@ -40,6 +57,7 @@ const SingleSelect = <V, T extends OptionType<V>>({
40
57
  }: SingleSelectProps<V, T>) => {
41
58
  const { isKeyboardVisible, keyboardHeight } = useKeyboard();
42
59
  const [open, setOpen] = useState(false);
60
+ const sectionListRef = useRef<SectionList<T, SectionType>>(null);
43
61
  const sections = toSections(options);
44
62
  const flatOptions = toFlatOptions(options);
45
63
  const displayedValue = flatOptions.find(opt => value === opt.value)?.text;
@@ -69,6 +87,11 @@ const SingleSelect = <V, T extends OptionType<V>>({
69
87
  pointerEvents="none"
70
88
  style={style}
71
89
  testID={testID}
90
+ renderInputValue={
91
+ renderSelectedValue !== undefined
92
+ ? props => renderSelectedValue(value, props)
93
+ : undefined
94
+ }
72
95
  />
73
96
  </View>
74
97
  </TouchableOpacity>
@@ -81,6 +104,12 @@ const SingleSelect = <V, T extends OptionType<V>>({
81
104
  style={{
82
105
  paddingBottom: isKeyboardVisible ? keyboardHeight : 0,
83
106
  }}
107
+ onAnimationEnd={() => {
108
+ if (open === true) {
109
+ const scrollParams = getScrollParams(value, sections);
110
+ sectionListRef.current?.scrollToLocation(scrollParams);
111
+ }
112
+ }}
84
113
  >
85
114
  {onQueryChange && (
86
115
  <StyledSearchBar>
@@ -104,6 +133,7 @@ const SingleSelect = <V, T extends OptionType<V>>({
104
133
  setOpen(false);
105
134
  onConfirm(selectedValue);
106
135
  }}
136
+ sectionListRef={sectionListRef}
107
137
  />
108
138
  </BottomSheet>
109
139
  </>