react-native-timer-picker 1.10.3 → 2.0.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.
- package/README.md +81 -52
- package/dist/commonjs/components/DurationScroll/index.js +77 -20
- package/dist/commonjs/components/DurationScroll/index.js.map +1 -1
- package/dist/commonjs/components/DurationScroll/types.js.map +1 -1
- package/dist/commonjs/components/TimerPicker/index.js +23 -10
- package/dist/commonjs/components/TimerPicker/index.js.map +1 -1
- package/dist/commonjs/components/TimerPicker/types.js.map +1 -1
- package/dist/commonjs/components/TimerPickerModal/index.js +10 -7
- package/dist/commonjs/components/TimerPickerModal/index.js.map +1 -1
- package/dist/commonjs/components/TimerPickerModal/styles.js +87 -54
- package/dist/commonjs/components/TimerPickerModal/styles.js.map +1 -1
- package/dist/commonjs/tests/DurationScroll.test.js +3 -3
- package/dist/commonjs/tests/DurationScroll.test.js.map +1 -1
- package/dist/commonjs/tests/Modal.test.js +3 -3
- package/dist/commonjs/tests/Modal.test.js.map +1 -1
- package/dist/commonjs/tests/TimerPicker.test.js +4 -4
- package/dist/commonjs/tests/TimerPicker.test.js.map +1 -1
- package/dist/commonjs/tests/TimerPickerModal.test.js +6 -6
- package/dist/commonjs/tests/TimerPickerModal.test.js.map +1 -1
- package/dist/commonjs/utils/generateNumbers.js +4 -3
- package/dist/commonjs/utils/generateNumbers.js.map +1 -1
- package/dist/commonjs/utils/getAdjustedLimit.js +5 -5
- package/dist/commonjs/utils/getAdjustedLimit.js.map +1 -1
- package/dist/commonjs/utils/getDurationAndIndexFromScrollOffset.js +2 -1
- package/dist/commonjs/utils/getDurationAndIndexFromScrollOffset.js.map +1 -1
- package/dist/commonjs/utils/getInitialScrollIndex.js +2 -1
- package/dist/commonjs/utils/getInitialScrollIndex.js.map +1 -1
- package/dist/commonjs/utils/getSafeInitialValue.js +13 -0
- package/dist/commonjs/utils/getSafeInitialValue.js.map +1 -0
- package/dist/module/components/DurationScroll/index.js +77 -20
- package/dist/module/components/DurationScroll/index.js.map +1 -1
- package/dist/module/components/DurationScroll/types.js.map +1 -1
- package/dist/module/components/TimerPicker/index.js +23 -10
- package/dist/module/components/TimerPicker/index.js.map +1 -1
- package/dist/module/components/TimerPicker/types.js.map +1 -1
- package/dist/module/components/TimerPickerModal/index.js +10 -7
- package/dist/module/components/TimerPickerModal/index.js.map +1 -1
- package/dist/module/components/TimerPickerModal/styles.js +87 -54
- package/dist/module/components/TimerPickerModal/styles.js.map +1 -1
- package/dist/module/tests/DurationScroll.test.js +3 -3
- package/dist/module/tests/DurationScroll.test.js.map +1 -1
- package/dist/module/tests/Modal.test.js +3 -3
- package/dist/module/tests/Modal.test.js.map +1 -1
- package/dist/module/tests/TimerPicker.test.js +4 -4
- package/dist/module/tests/TimerPicker.test.js.map +1 -1
- package/dist/module/tests/TimerPickerModal.test.js +6 -6
- package/dist/module/tests/TimerPickerModal.test.js.map +1 -1
- package/dist/module/utils/generateNumbers.js +4 -3
- package/dist/module/utils/generateNumbers.js.map +1 -1
- package/dist/module/utils/getAdjustedLimit.js +5 -5
- package/dist/module/utils/getAdjustedLimit.js.map +1 -1
- package/dist/module/utils/getDurationAndIndexFromScrollOffset.js +2 -1
- package/dist/module/utils/getDurationAndIndexFromScrollOffset.js.map +1 -1
- package/dist/module/utils/getInitialScrollIndex.js +2 -1
- package/dist/module/utils/getInitialScrollIndex.js.map +1 -1
- package/dist/module/utils/getSafeInitialValue.js +6 -0
- package/dist/module/utils/getSafeInitialValue.js.map +1 -0
- package/dist/typescript/components/DurationScroll/types.d.ts +4 -1
- package/dist/typescript/components/TimerPicker/types.d.ts +7 -0
- package/dist/typescript/components/TimerPickerModal/styles.d.ts +117 -8
- package/dist/typescript/utils/generateNumbers.d.ts +2 -0
- package/dist/typescript/utils/getAdjustedLimit.d.ts +1 -1
- package/dist/typescript/utils/getDurationAndIndexFromScrollOffset.d.ts +1 -0
- package/dist/typescript/utils/getInitialScrollIndex.d.ts +1 -0
- package/dist/typescript/utils/getSafeInitialValue.d.ts +9 -0
- package/package.json +14 -10
package/README.md
CHANGED
|
@@ -29,6 +29,7 @@ Includes iOS-style haptic and audio feedback 🍏
|
|
|
29
29
|
- [Custom Styles 👗](#custom-styles-)
|
|
30
30
|
- [Performance](#performance)
|
|
31
31
|
- [Custom FlatList](#custom-flatlist)
|
|
32
|
+
- [Generic feedback](#generic-feedback)
|
|
32
33
|
- [TimerPickerModal ⏰](#timerpickermodal-)
|
|
33
34
|
- [Custom Styles 👕](#custom-styles--1)
|
|
34
35
|
- [Methods 🔄](#methods-)
|
|
@@ -72,15 +73,17 @@ If you want the numbers to fade in/out at the top and bottom of the picker, you
|
|
|
72
73
|
|
|
73
74
|
### Haptic Feedback
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
Enable haptic feedback with the [expo-haptics](https://www.npmjs.com/package/expo-haptics) module:
|
|
76
77
|
|
|
77
78
|
`import * as Haptics from "expo-haptics";`
|
|
78
79
|
|
|
79
80
|
**To enable haptic feedback, you need to supply the imported `Haptics` namespace as a prop to either TimerPickerModal or TimerPicker.**
|
|
80
81
|
|
|
82
|
+
[Generic feedback](#generic-feedback) support is possible with the `pickerFeeback` prop.
|
|
83
|
+
|
|
81
84
|
### Audio Feedback (Click Sound)
|
|
82
85
|
|
|
83
|
-
|
|
86
|
+
Enable audio feedback with the [expo-av](https://www.npmjs.com/package/expo-av) module:
|
|
84
87
|
|
|
85
88
|
`import { Audio } from "expo-av";`
|
|
86
89
|
|
|
@@ -89,6 +92,8 @@ This is currently only supported on Expo with the [expo-av](https://www.npmjs.co
|
|
|
89
92
|
Please note that the default click sound uses a hosted mp3 file. To make the click sound work offline, you need to supply your own
|
|
90
93
|
sound asset through the `clickSoundAsset` prop. You can download the default click sound [here](https://drive.google.com/uc?export=download&id=10e1YkbNsRh-vGx1jmS1Nntz8xzkBp4_I).
|
|
91
94
|
|
|
95
|
+
[Generic feedback](#generic-feedback) support is possible with the `pickerFeeback` prop.
|
|
96
|
+
|
|
92
97
|
<br>
|
|
93
98
|
|
|
94
99
|
## Installation 🚀
|
|
@@ -424,45 +429,52 @@ return (
|
|
|
424
429
|
|
|
425
430
|
### TimerPicker ⏲️
|
|
426
431
|
|
|
427
|
-
| Prop | Description
|
|
428
|
-
| :------------------------------: |
|
|
429
|
-
| onDurationChange | Callback when the duration changes
|
|
430
|
-
| initialValue | Initial value for the picker
|
|
431
|
-
| hideHours | Hide the hours picker
|
|
432
|
-
| hideMinutes | Hide the minutes picker
|
|
433
|
-
| hideSeconds | Hide the seconds picker
|
|
434
|
-
| hoursPickerIsDisabled | Disable the hours picker picker
|
|
435
|
-
| minutesPickerIsDisabled | Disable the minutes picker picker
|
|
436
|
-
| secondsPickerIsDisabled | Disable the seconds picker picker
|
|
437
|
-
| hourLimit | Limit on the hours it is possible to select
|
|
438
|
-
| minuteLimit | Limit on the minutes it is possible to select
|
|
439
|
-
| secondLimit | Limit on the seconds it is possible to select
|
|
440
|
-
|
|
|
441
|
-
|
|
|
442
|
-
|
|
|
443
|
-
|
|
|
444
|
-
|
|
|
445
|
-
|
|
|
446
|
-
|
|
|
447
|
-
|
|
|
448
|
-
|
|
|
449
|
-
|
|
|
450
|
-
|
|
|
451
|
-
|
|
|
452
|
-
|
|
|
453
|
-
|
|
|
454
|
-
|
|
|
455
|
-
|
|
|
456
|
-
|
|
|
457
|
-
|
|
|
458
|
-
|
|
|
459
|
-
|
|
|
460
|
-
|
|
|
461
|
-
|
|
|
462
|
-
|
|
|
463
|
-
|
|
|
464
|
-
|
|
|
465
|
-
|
|
|
432
|
+
| Prop | Description | Type | Default | Required |
|
|
433
|
+
| :------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------: | :------: |
|
|
434
|
+
| onDurationChange | Callback when the duration changes | `(duration: { hours: number, minutes: number, seconds: number }) => void` | - | false |
|
|
435
|
+
| initialValue | Initial value for the picker | `{ hours?: number, minutes?: number, seconds?: number }` | - | false |
|
|
436
|
+
| hideHours | Hide the hours picker | Boolean | false | false |
|
|
437
|
+
| hideMinutes | Hide the minutes picker | Boolean | false | false |
|
|
438
|
+
| hideSeconds | Hide the seconds picker | Boolean | false | false |
|
|
439
|
+
| hoursPickerIsDisabled | Disable the hours picker picker | Boolean | false | false |
|
|
440
|
+
| minutesPickerIsDisabled | Disable the minutes picker picker | Boolean | false | false |
|
|
441
|
+
| secondsPickerIsDisabled | Disable the seconds picker picker | Boolean | false | false |
|
|
442
|
+
| hourLimit | Limit on the hours it is possible to select | `{ max?: Number, min?: Number }` | - | false |
|
|
443
|
+
| minuteLimit | Limit on the minutes it is possible to select | `{ max?: Number, min?: Number }` | - | false |
|
|
444
|
+
| secondLimit | Limit on the seconds it is possible to select | `{ max?: Number, min?: Number }` | - | false |
|
|
445
|
+
| maximumHours | The highest value on the hours picker | Number | 23 | false |
|
|
446
|
+
| maximumMinutes | The highest value on the minutes picker | Number | 59 | false |
|
|
447
|
+
| maximumSeconds | The highest value on the seconds picker | Number | 59 | false |
|
|
448
|
+
| hourInterval | The interval between values on the hours picker | Number | 1 | false |
|
|
449
|
+
| minuteInterval | The interval between values on the minutes picker | Number | 1 | false |
|
|
450
|
+
| secondInterval | The interval between values on the seconds picker | Number | 1 | false |
|
|
451
|
+
| hourLabel | Label for the hours picker | String \| React.ReactElement | h | false |
|
|
452
|
+
| minuteLabel | Label for the minutes picker | String \| React.ReactElement | m | false |
|
|
453
|
+
| secondLabel | Label for the seconds picker | String \| React.ReactElement | s | false |
|
|
454
|
+
| padHoursWithZero | Pad single-digit hours in the picker with a zero | Boolean | false | false |
|
|
455
|
+
| padMinutesWithZero | Pad single-digit minutes in the picker with a zero | Boolean | true | false |
|
|
456
|
+
| padSecondsWithZero | Pad single-digit seconds in the picker with a zero | Boolean | true | false |
|
|
457
|
+
| padWithNItems | Number of items to pad the picker with on either side | Number | 1 | false |
|
|
458
|
+
| aggressivelyGetLatestDuration | Set to True to ask DurationScroll to aggressively update the latestDuration ref | Boolean | false | false |
|
|
459
|
+
| allowFontScaling | Allow font in the picker to scale with accessibility settings | Boolean | false | false |
|
|
460
|
+
| use12HourPicker | Switch the hour picker to 12-hour format with an AM / PM label | Boolean | false | false |
|
|
461
|
+
| amLabel | Set the AM label if using the 12-hour picker | String | am | false |
|
|
462
|
+
| pmLabel | Set the PM label if using the 12-hour picker | String | pm | false |
|
|
463
|
+
| repeatHourNumbersNTimes | Set the number of times the list of hours is repeated in the picker | Number | 7 | false |
|
|
464
|
+
| repeatMinuteNumbersNTimes | Set the number of times the list of minutes is repeated in the picker | Number | 3 | false |
|
|
465
|
+
| repeatSecondNumbersNTimes | Set the number of times the list of seconds is repeated in the picker | Number | 3 | false |
|
|
466
|
+
| disableInfiniteScroll | Disable the infinite scroll feature | Boolean | false | false |
|
|
467
|
+
| LinearGradient | Linear Gradient Component | [expo-linear-gradient](https://www.npmjs.com/package/expo-linear-gradient).LinearGradient or [react-native-linear-gradient](https://www.npmjs.com/package/react-native-linear-gradient).default | - | false |
|
|
468
|
+
| Haptics | Haptics Namespace (required for Haptic feedback) | [expo-haptics](https://www.npmjs.com/package/expo-haptics) | - | false |
|
|
469
|
+
| Audio | Audio Class (required for audio feedback i.e. click sound) | [expo-av](https://www.npmjs.com/package/expo-av).Audio | - | false |
|
|
470
|
+
| pickerFeedback | Generic picker feedback as alternative to the below Expo feedback support | `() => void \| Promise<void> ` | - | false |
|
|
471
|
+
| FlatList | FlatList component used internally to implement each picker (hour, minutes and seconds). More info [below](#custom-flatlist) | [react-native](https://reactnative.dev/docs/flatlist).FlatList | `FlatList` from `react-native` | false |
|
|
472
|
+
| clickSoundAsset | Custom sound asset for click sound (required for offline click sound - download default [here](https://drive.google.com/uc?export=download&id=10e1YkbNsRh-vGx1jmS1Nntz8xzkBp4_I)) | require(.../somefolderpath) or {uri: www.someurl} | - | false |
|
|
473
|
+
| pickerContainerProps | Props for the picker container | `React.ComponentProps<typeof View>` | - | false |
|
|
474
|
+
| pickerGradientOverlayProps | Props for both gradient overlays | `Partial<LinearGradientProps>` | - | false |
|
|
475
|
+
| topPickerGradientOverlayProps | Props for the top gradient overlay | `Partial<LinearGradientProps>` | - | false |
|
|
476
|
+
| bottomPickerGradientOverlayProps | Props for the bottom gradient overlay | `Partial<LinearGradientProps>` | - | false |
|
|
477
|
+
| styles | Custom styles for the timer picker | [CustomTimerPickerStyles](#custom-styles-) | - | false |
|
|
466
478
|
|
|
467
479
|
#### Custom Styles 👗
|
|
468
480
|
|
|
@@ -486,7 +498,6 @@ The following custom styles can be supplied to re-style the component in any way
|
|
|
486
498
|
|
|
487
499
|
Note the minor limitations to the allowed styles for `pickerContainer` and `pickerItemContainer`. These are made because these styles are used for internal calculations and all possible `backgroundColor`/`height` types are not supported.
|
|
488
500
|
|
|
489
|
-
|
|
490
501
|
#### Performance
|
|
491
502
|
|
|
492
503
|
When the `disableInfiniteScroll` prop is not set, the picker gives the appearance of an infinitely scrolling picker by auto-scrolling forward/back when you near the start/end of the list. When the picker auto-scrolls, a momentary flicker is visible if you are scrolling very slowly.
|
|
@@ -495,7 +506,6 @@ To mitigate for this, you can modify the `repeatHourNumbersNTimes`, `repeatMinut
|
|
|
495
506
|
|
|
496
507
|
Note that you can avoid the auto-scroll flickering entirely by disabling infinite scroll. You could then set the above props to high values, so that a user has to scroll far down/up the list to reach the end of the list.
|
|
497
508
|
|
|
498
|
-
|
|
499
509
|
#### Custom FlatList
|
|
500
510
|
|
|
501
511
|
The library offers the ability to provide a custom component for the `<FlatList />`, instead of the default React Native component. This allows for more flexibility and integration with libraries like [react-native-gesture-handler](react-native-gesture-handler) or other components built on top of it, like [https://ui.gorhom.dev/components/bottom-sheet](https://ui.gorhom.dev/components/bottom-sheet).
|
|
@@ -518,6 +528,23 @@ import { TimerPicker } from "react-native-timer-picker";
|
|
|
518
528
|
**Important**:
|
|
519
529
|
The custom component needs to have the same interface as React Native's `<FlatList />` in order for it to work as expected. A complete reference of the current usage can be found [here](/src/components/DurationScroll/index.tsx)
|
|
520
530
|
|
|
531
|
+
#### Generic feedback
|
|
532
|
+
|
|
533
|
+
To enable haptic feedback from the non-Expo module [react-native-haptic-feedback](https://github.com/mkuczera/react-native-haptic-feedback) or provide feedback in any other form you can use the generic feedback callback prop `pickerFeedback`. This function is called whenever any of the pickers tick onto a new number.
|
|
534
|
+
|
|
535
|
+
```Jsx
|
|
536
|
+
import { trigger } from 'react-native-haptic-feedback';
|
|
537
|
+
import { TimerPicker } from "react-native-timer-picker";
|
|
538
|
+
|
|
539
|
+
// ...
|
|
540
|
+
|
|
541
|
+
<TimerPicker
|
|
542
|
+
{...props}
|
|
543
|
+
pickerFeedback={() => trigger('impactLight')}
|
|
544
|
+
/>
|
|
545
|
+
|
|
546
|
+
```
|
|
547
|
+
|
|
521
548
|
### TimerPickerModal ⏰
|
|
522
549
|
|
|
523
550
|
The TimerPickerModal component accepts all [TimerPicker props](#timerpicker-️), and the below additional props.
|
|
@@ -609,16 +636,12 @@ Contributions to this project are more than welcome.
|
|
|
609
636
|
To get this project running locally:
|
|
610
637
|
|
|
611
638
|
1. Clone the Git repo.
|
|
612
|
-
2. Run `yarn`
|
|
613
|
-
3. Run `yarn setup` from the project root (this installs the example's additional dependencies)
|
|
614
|
-
4. Run `yarn start` to start the example in Expo Go.
|
|
615
|
-
5. Start adding cool stuff! Your changes should be immediately reflected in the Expo Go app.
|
|
639
|
+
2. Run `yarn setup` from the project root (this installs the project dependencies and the examples' additional dependencies)
|
|
616
640
|
|
|
617
|
-
You can
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
4. Run `yarn start-bare:android` or `start-bare:ios` to start the project on an emulator/device.
|
|
641
|
+
You can then start either the Expo example or the bare React Native example:
|
|
642
|
+
|
|
643
|
+
- For Expo, run `yarn start` to start the Expo example in Expo Go.
|
|
644
|
+
- For bare React Native, run `yarn start-bare:android` or `start-bare:ios` to start the project on an emulator/device.
|
|
622
645
|
|
|
623
646
|
### GitHub Guidelines
|
|
624
647
|
|
|
@@ -630,6 +653,12 @@ There are two permenant branches: `main` and `develop`. You should never work di
|
|
|
630
653
|
|
|
631
654
|
<br>
|
|
632
655
|
|
|
656
|
+
## Limitations ⚠
|
|
657
|
+
|
|
658
|
+
The project is not compatibile with React Native versions prior to `v0.72.0` due to this [React Native issue](https://github.com/facebook/react-native/issues/36329).
|
|
659
|
+
|
|
660
|
+
<br>
|
|
661
|
+
|
|
633
662
|
## License 📝
|
|
634
663
|
|
|
635
664
|
This project is licensed under the [MIT License](LICENSE).
|
|
@@ -26,54 +26,78 @@ const DurationScroll = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
|
|
|
26
26
|
FlatList = _reactNative.FlatList,
|
|
27
27
|
Haptics,
|
|
28
28
|
initialValue = 0,
|
|
29
|
+
interval,
|
|
29
30
|
is12HourPicker,
|
|
30
31
|
isDisabled,
|
|
31
32
|
label,
|
|
32
33
|
limit,
|
|
33
34
|
LinearGradient,
|
|
34
|
-
|
|
35
|
+
maximumValue,
|
|
35
36
|
onDurationChange,
|
|
36
37
|
padNumbersWithZero = false,
|
|
37
38
|
padWithNItems,
|
|
39
|
+
pickerFeedback,
|
|
38
40
|
pickerGradientOverlayProps,
|
|
39
41
|
pmLabel,
|
|
40
42
|
repeatNumbersNTimes = 3,
|
|
43
|
+
repeatNumbersNTimesNotExplicitlySet,
|
|
41
44
|
styles,
|
|
42
45
|
testID,
|
|
43
46
|
topPickerGradientOverlayProps
|
|
44
47
|
} = props;
|
|
48
|
+
const numberOfItems = (0, _react.useMemo)(() => {
|
|
49
|
+
// guard against negative maximum values
|
|
50
|
+
if (maximumValue < 0) {
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
return Math.floor(maximumValue / interval) + 1;
|
|
54
|
+
}, [interval, maximumValue]);
|
|
45
55
|
const safeRepeatNumbersNTimes = (0, _react.useMemo)(() => {
|
|
56
|
+
// do not repeat numbers if there is only one option
|
|
57
|
+
if (numberOfItems === 1) {
|
|
58
|
+
return 1;
|
|
59
|
+
}
|
|
46
60
|
if (!disableInfiniteScroll && repeatNumbersNTimes < 2) {
|
|
47
61
|
return 2;
|
|
48
|
-
} else if (repeatNumbersNTimes < 1) {
|
|
62
|
+
} else if (repeatNumbersNTimes < 1 || isNaN(repeatNumbersNTimes)) {
|
|
49
63
|
return 1;
|
|
50
64
|
}
|
|
65
|
+
|
|
66
|
+
// if this variable is not explicitly set, we calculate a reasonable value based on
|
|
67
|
+
// the number of items in the picker, avoiding regular jumps up/down the list
|
|
68
|
+
// whilst avoiding rendering too many items in the picker
|
|
69
|
+
if (repeatNumbersNTimesNotExplicitlySet) {
|
|
70
|
+
return Math.max(Math.round(180 / numberOfItems), 1);
|
|
71
|
+
}
|
|
51
72
|
return Math.round(repeatNumbersNTimes);
|
|
52
|
-
}, [disableInfiniteScroll, repeatNumbersNTimes]);
|
|
73
|
+
}, [disableInfiniteScroll, numberOfItems, repeatNumbersNTimes, repeatNumbersNTimesNotExplicitlySet]);
|
|
53
74
|
const numbersForFlatList = (0, _react.useMemo)(() => {
|
|
54
75
|
if (is12HourPicker) {
|
|
55
76
|
return (0, _generateNumbers.generate12HourNumbers)({
|
|
56
77
|
padNumbersWithZero,
|
|
57
78
|
repeatNTimes: safeRepeatNumbersNTimes,
|
|
58
79
|
disableInfiniteScroll,
|
|
59
|
-
padWithNItems
|
|
80
|
+
padWithNItems,
|
|
81
|
+
interval
|
|
60
82
|
});
|
|
61
83
|
}
|
|
62
84
|
return (0, _generateNumbers.generateNumbers)(numberOfItems, {
|
|
63
85
|
padNumbersWithZero,
|
|
64
86
|
repeatNTimes: safeRepeatNumbersNTimes,
|
|
65
87
|
disableInfiniteScroll,
|
|
66
|
-
padWithNItems
|
|
88
|
+
padWithNItems,
|
|
89
|
+
interval
|
|
67
90
|
});
|
|
68
|
-
}, [disableInfiniteScroll, is12HourPicker, numberOfItems, padNumbersWithZero, padWithNItems, safeRepeatNumbersNTimes]);
|
|
91
|
+
}, [disableInfiniteScroll, is12HourPicker, interval, numberOfItems, padNumbersWithZero, padWithNItems, safeRepeatNumbersNTimes]);
|
|
69
92
|
const initialScrollIndex = (0, _react.useMemo)(() => (0, _getInitialScrollIndex.getInitialScrollIndex)({
|
|
70
93
|
disableInfiniteScroll,
|
|
94
|
+
interval,
|
|
71
95
|
numberOfItems,
|
|
72
96
|
padWithNItems,
|
|
73
97
|
repeatNumbersNTimes: safeRepeatNumbersNTimes,
|
|
74
98
|
value: initialValue
|
|
75
|
-
}), [disableInfiniteScroll, initialValue, numberOfItems, padWithNItems, safeRepeatNumbersNTimes]);
|
|
76
|
-
const adjustedLimited = (0, _react.useMemo)(() => (0, _getAdjustedLimit.getAdjustedLimit)(limit, numberOfItems), [limit, numberOfItems]);
|
|
99
|
+
}), [disableInfiniteScroll, initialValue, interval, numberOfItems, padWithNItems, safeRepeatNumbersNTimes]);
|
|
100
|
+
const adjustedLimited = (0, _react.useMemo)(() => (0, _getAdjustedLimit.getAdjustedLimit)(limit, numberOfItems, interval), [interval, limit, numberOfItems]);
|
|
77
101
|
const numberOfItemsToShow = 1 + padWithNItems * 2;
|
|
78
102
|
|
|
79
103
|
// keep track of the latest duration as it scrolls
|
|
@@ -139,12 +163,13 @@ const DurationScroll = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
|
|
|
139
163
|
// this function is only used when the picker is in a modal and/or has Haptic/Audio feedback
|
|
140
164
|
// it is used to ensure that the modal gets the latest duration on clicking
|
|
141
165
|
// the confirm button, even if the scrollview is still scrolling
|
|
142
|
-
if (!aggressivelyGetLatestDuration && !Haptics && !Audio) {
|
|
166
|
+
if (!aggressivelyGetLatestDuration && !Haptics && !Audio && !pickerFeedback) {
|
|
143
167
|
return;
|
|
144
168
|
}
|
|
145
169
|
if (aggressivelyGetLatestDuration) {
|
|
146
170
|
const newValues = (0, _getDurationAndIndexFromScrollOffset.getDurationAndIndexFromScrollOffset)({
|
|
147
171
|
disableInfiniteScroll,
|
|
172
|
+
interval,
|
|
148
173
|
itemHeight: styles.pickerItemContainer.height,
|
|
149
174
|
numberOfItems,
|
|
150
175
|
padWithNItems,
|
|
@@ -160,7 +185,7 @@ const DurationScroll = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
|
|
|
160
185
|
latestDuration.current = newValues.duration;
|
|
161
186
|
}
|
|
162
187
|
}
|
|
163
|
-
if (Haptics || Audio) {
|
|
188
|
+
if (Haptics || Audio || pickerFeedback) {
|
|
164
189
|
const feedbackIndex = Math.round((e.nativeEvent.contentOffset.y + styles.pickerItemContainer.height / 2) / styles.pickerItemContainer.height);
|
|
165
190
|
if (feedbackIndex !== lastFeedbackIndex.current) {
|
|
166
191
|
// this check stops the feedback firing when the component mounts
|
|
@@ -178,16 +203,24 @@ const DurationScroll = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
|
|
|
178
203
|
} catch {
|
|
179
204
|
// do nothing
|
|
180
205
|
}
|
|
206
|
+
|
|
207
|
+
// fire custom feedback if available
|
|
208
|
+
try {
|
|
209
|
+
pickerFeedback === null || pickerFeedback === void 0 || pickerFeedback();
|
|
210
|
+
} catch {
|
|
211
|
+
// do nothing
|
|
212
|
+
}
|
|
181
213
|
}
|
|
182
214
|
lastFeedbackIndex.current = feedbackIndex;
|
|
183
215
|
}
|
|
184
216
|
}
|
|
185
217
|
},
|
|
186
218
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
187
|
-
[adjustedLimited.max, adjustedLimited.min, aggressivelyGetLatestDuration, clickSound, disableInfiniteScroll, numberOfItems, padWithNItems, styles.pickerItemContainer.height]);
|
|
219
|
+
[adjustedLimited.max, adjustedLimited.min, aggressivelyGetLatestDuration, clickSound, disableInfiniteScroll, interval, numberOfItems, padWithNItems, styles.pickerItemContainer.height]);
|
|
188
220
|
const onMomentumScrollEnd = (0, _react.useCallback)(e => {
|
|
189
221
|
const newValues = (0, _getDurationAndIndexFromScrollOffset.getDurationAndIndexFromScrollOffset)({
|
|
190
222
|
disableInfiniteScroll,
|
|
223
|
+
interval,
|
|
191
224
|
itemHeight: styles.pickerItemContainer.height,
|
|
192
225
|
numberOfItems,
|
|
193
226
|
padWithNItems,
|
|
@@ -217,11 +250,14 @@ const DurationScroll = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
|
|
|
217
250
|
newValues.duration = adjustedLimited.min;
|
|
218
251
|
}
|
|
219
252
|
onDurationChange(newValues.duration);
|
|
220
|
-
}, [
|
|
253
|
+
}, [disableInfiniteScroll, interval, styles.pickerItemContainer.height, numberOfItems, padWithNItems, adjustedLimited.max, adjustedLimited.min, onDurationChange, numbersForFlatList.length]);
|
|
221
254
|
const onViewableItemsChanged = (0, _react.useCallback)(({
|
|
222
255
|
viewableItems
|
|
223
256
|
}) => {
|
|
224
257
|
var _viewableItems$, _viewableItems$2;
|
|
258
|
+
if (numberOfItems === 1) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
225
261
|
if ((_viewableItems$ = viewableItems[0]) !== null && _viewableItems$ !== void 0 && _viewableItems$.index && viewableItems[0].index < numberOfItems * 0.5) {
|
|
226
262
|
var _flatListRef$current3;
|
|
227
263
|
(_flatListRef$current3 = flatListRef.current) === null || _flatListRef$current3 === void 0 || _flatListRef$current3.scrollToIndex({
|
|
@@ -236,17 +272,36 @@ const DurationScroll = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
|
|
|
236
272
|
});
|
|
237
273
|
}
|
|
238
274
|
}, [numberOfItems, safeRepeatNumbersNTimes]);
|
|
275
|
+
const [viewabilityConfigCallbackPairs, setViewabilityConfigCallbackPairs] = (0, _react.useState)(!disableInfiniteScroll ? [{
|
|
276
|
+
viewabilityConfig: {
|
|
277
|
+
viewAreaCoveragePercentThreshold: 0
|
|
278
|
+
},
|
|
279
|
+
onViewableItemsChanged: onViewableItemsChanged
|
|
280
|
+
}] : undefined);
|
|
281
|
+
const [flatListRenderKey, setFlatListRenderKey] = (0, _react.useState)(0);
|
|
282
|
+
const initialRender = (0, _react.useRef)(true);
|
|
283
|
+
(0, _react.useEffect)(() => {
|
|
284
|
+
// don't run on first render
|
|
285
|
+
if (initialRender.current) {
|
|
286
|
+
initialRender.current = false;
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// if the onViewableItemsChanged callback changes, we need to update viewabilityConfigCallbackPairs
|
|
291
|
+
// which requires the FlatList to be remounted, hence the increase of the FlatList key
|
|
292
|
+
setFlatListRenderKey(prev => prev + 1);
|
|
293
|
+
setViewabilityConfigCallbackPairs(!disableInfiniteScroll ? [{
|
|
294
|
+
viewabilityConfig: {
|
|
295
|
+
viewAreaCoveragePercentThreshold: 0
|
|
296
|
+
},
|
|
297
|
+
onViewableItemsChanged: onViewableItemsChanged
|
|
298
|
+
}] : undefined);
|
|
299
|
+
}, [disableInfiniteScroll, onViewableItemsChanged]);
|
|
239
300
|
const getItemLayout = (0, _react.useCallback)((_, index) => ({
|
|
240
301
|
length: styles.pickerItemContainer.height,
|
|
241
302
|
offset: styles.pickerItemContainer.height * index,
|
|
242
303
|
index
|
|
243
304
|
}), [styles.pickerItemContainer.height]);
|
|
244
|
-
const viewabilityConfigCallbackPairs = (0, _react.useRef)([{
|
|
245
|
-
viewabilityConfig: {
|
|
246
|
-
viewAreaCoveragePercentThreshold: 0
|
|
247
|
-
},
|
|
248
|
-
onViewableItemsChanged: onViewableItemsChanged
|
|
249
|
-
}]);
|
|
250
305
|
(0, _react.useImperativeHandle)(ref, () => ({
|
|
251
306
|
reset: options => {
|
|
252
307
|
var _flatListRef$current5;
|
|
@@ -261,6 +316,7 @@ const DurationScroll = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
|
|
|
261
316
|
animated: (options === null || options === void 0 ? void 0 : options.animated) ?? false,
|
|
262
317
|
index: (0, _getInitialScrollIndex.getInitialScrollIndex)({
|
|
263
318
|
disableInfiniteScroll,
|
|
319
|
+
interval,
|
|
264
320
|
numberOfItems,
|
|
265
321
|
padWithNItems,
|
|
266
322
|
repeatNumbersNTimes: safeRepeatNumbersNTimes,
|
|
@@ -278,6 +334,7 @@ const DurationScroll = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
|
|
|
278
334
|
}, isDisabled && styles.disabledPickerContainer],
|
|
279
335
|
testID: testID
|
|
280
336
|
}, /*#__PURE__*/_react.default.createElement(FlatList, {
|
|
337
|
+
key: flatListRenderKey,
|
|
281
338
|
ref: flatListRef,
|
|
282
339
|
data: numbersForFlatList,
|
|
283
340
|
decelerationRate: 0.88,
|
|
@@ -292,11 +349,11 @@ const DurationScroll = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
|
|
|
292
349
|
scrollEventThrottle: 16,
|
|
293
350
|
showsVerticalScrollIndicator: false,
|
|
294
351
|
snapToAlignment: "start"
|
|
295
|
-
// used in place of
|
|
352
|
+
// used in place of snapToInterval due to bug on Android
|
|
296
353
|
,
|
|
297
354
|
snapToOffsets: [...Array(numbersForFlatList.length)].map((_, i) => i * styles.pickerItemContainer.height),
|
|
298
355
|
testID: "duration-scroll-flatlist",
|
|
299
|
-
viewabilityConfigCallbackPairs:
|
|
356
|
+
viewabilityConfigCallbackPairs: viewabilityConfigCallbackPairs,
|
|
300
357
|
windowSize: numberOfItemsToShow
|
|
301
358
|
}), /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
302
359
|
pointerEvents: "none",
|