react-native-timer-picker 1.2.7 → 1.2.9

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 (110) hide show
  1. package/dist/commonjs/components/Modal/Modal.styles.js +32 -0
  2. package/dist/commonjs/components/Modal/Modal.styles.js.map +1 -0
  3. package/dist/commonjs/components/Modal/index.js +108 -0
  4. package/dist/commonjs/components/Modal/index.js.map +1 -0
  5. package/dist/commonjs/components/TimerPicker/DurationScroll.js +210 -0
  6. package/dist/commonjs/components/TimerPicker/DurationScroll.js.map +1 -0
  7. package/dist/commonjs/components/TimerPicker/TimerPicker.styles.js +67 -0
  8. package/dist/commonjs/components/TimerPicker/TimerPicker.styles.js.map +1 -0
  9. package/dist/commonjs/components/TimerPicker/index.js +130 -0
  10. package/dist/commonjs/components/TimerPicker/index.js.map +1 -0
  11. package/dist/commonjs/components/TimerPickerModal.styles.js +69 -0
  12. package/dist/commonjs/components/TimerPickerModal.styles.js.map +1 -0
  13. package/dist/commonjs/components/index.js +156 -0
  14. package/dist/commonjs/components/index.js.map +1 -0
  15. package/dist/commonjs/index.js +21 -0
  16. package/dist/commonjs/index.js.map +1 -0
  17. package/dist/commonjs/tests/DurationScroll.test.js +56 -0
  18. package/dist/commonjs/tests/DurationScroll.test.js.map +1 -0
  19. package/dist/commonjs/tests/Modal.test.js +40 -0
  20. package/dist/commonjs/tests/Modal.test.js.map +1 -0
  21. package/dist/commonjs/tests/TimerPicker.test.js +37 -0
  22. package/dist/commonjs/tests/TimerPicker.test.js.map +1 -0
  23. package/dist/commonjs/tests/TimerPickerModal.test.js +73 -0
  24. package/dist/commonjs/tests/TimerPickerModal.test.js.map +1 -0
  25. package/dist/commonjs/utils/colorToRgba.js +51 -0
  26. package/dist/commonjs/utils/colorToRgba.js.map +1 -0
  27. package/dist/commonjs/utils/generateNumbers.js +32 -0
  28. package/dist/commonjs/utils/generateNumbers.js.map +1 -0
  29. package/dist/commonjs/utils/getAdjustedLimit.js +32 -0
  30. package/dist/commonjs/utils/getAdjustedLimit.js.map +1 -0
  31. package/dist/commonjs/utils/getScrollIndex.js +17 -0
  32. package/dist/commonjs/utils/getScrollIndex.js.map +1 -0
  33. package/dist/commonjs/utils/padWithZero.js +15 -0
  34. package/dist/commonjs/utils/padWithZero.js.map +1 -0
  35. package/dist/module/components/Modal/Modal.styles.js +26 -0
  36. package/dist/module/components/Modal/Modal.styles.js.map +1 -0
  37. package/dist/module/components/Modal/index.js +100 -0
  38. package/dist/module/components/Modal/index.js.map +1 -0
  39. package/dist/module/components/TimerPicker/DurationScroll.js +202 -0
  40. package/dist/module/components/TimerPicker/DurationScroll.js.map +1 -0
  41. package/dist/module/components/TimerPicker/TimerPicker.styles.js +59 -0
  42. package/dist/module/components/TimerPicker/TimerPicker.styles.js.map +1 -0
  43. package/dist/module/components/TimerPicker/index.js +121 -0
  44. package/dist/module/components/TimerPicker/index.js.map +1 -0
  45. package/dist/module/components/TimerPickerModal.styles.js +61 -0
  46. package/dist/module/components/TimerPickerModal.styles.js.map +1 -0
  47. package/dist/module/components/index.js +147 -0
  48. package/dist/module/components/index.js.map +1 -0
  49. package/dist/module/index.js +3 -0
  50. package/dist/module/index.js.map +1 -0
  51. package/dist/module/tests/DurationScroll.test.js +53 -0
  52. package/dist/module/tests/DurationScroll.test.js.map +1 -0
  53. package/dist/module/tests/Modal.test.js +37 -0
  54. package/dist/module/tests/Modal.test.js.map +1 -0
  55. package/dist/module/tests/TimerPicker.test.js +34 -0
  56. package/dist/module/tests/TimerPicker.test.js.map +1 -0
  57. package/dist/module/tests/TimerPickerModal.test.js +70 -0
  58. package/dist/module/tests/TimerPickerModal.test.js.map +1 -0
  59. package/dist/module/utils/colorToRgba.js +44 -0
  60. package/dist/module/utils/colorToRgba.js.map +1 -0
  61. package/dist/module/utils/generateNumbers.js +25 -0
  62. package/dist/module/utils/generateNumbers.js.map +1 -0
  63. package/dist/module/utils/getAdjustedLimit.js +25 -0
  64. package/dist/module/utils/getAdjustedLimit.js.map +1 -0
  65. package/dist/module/utils/getScrollIndex.js +10 -0
  66. package/dist/module/utils/getScrollIndex.js.map +1 -0
  67. package/dist/module/utils/padWithZero.js +8 -0
  68. package/dist/module/utils/padWithZero.js.map +1 -0
  69. package/dist/typescript/index.d.ts +4 -0
  70. package/dist/{utils → typescript/utils}/colorToRgba.d.ts +1 -1
  71. package/dist/{utils → typescript/utils}/getScrollIndex.d.ts +1 -1
  72. package/package.json +29 -12
  73. package/{dist/components/Modal/Modal.styles.js → src/components/Modal/Modal.styles.ts} +4 -6
  74. package/src/components/Modal/index.tsx +134 -0
  75. package/src/components/TimerPicker/DurationScroll.tsx +337 -0
  76. package/src/components/TimerPicker/TimerPicker.styles.ts +87 -0
  77. package/src/components/TimerPicker/index.tsx +216 -0
  78. package/src/components/TimerPickerModal.styles.ts +87 -0
  79. package/src/components/index.tsx +243 -0
  80. package/src/index.ts +14 -0
  81. package/src/tests/DurationScroll.test.tsx +57 -0
  82. package/src/tests/Modal.test.tsx +34 -0
  83. package/src/tests/TimerPicker.test.tsx +27 -0
  84. package/src/tests/TimerPickerModal.test.tsx +70 -0
  85. package/{dist/utils/colorToRgba.js → src/utils/colorToRgba.ts} +18 -17
  86. package/src/utils/generateNumbers.ts +34 -0
  87. package/{dist/utils/getAdjustedLimit.js → src/utils/getAdjustedLimit.ts} +14 -7
  88. package/src/utils/getScrollIndex.ts +15 -0
  89. package/src/utils/padWithZero.ts +7 -0
  90. package/dist/components/Modal/index.js +0 -109
  91. package/dist/components/TimerPicker/DurationScroll.js +0 -211
  92. package/dist/components/TimerPicker/TimerPicker.styles.js +0 -41
  93. package/dist/components/TimerPicker/index.js +0 -81
  94. package/dist/components/TimerPickerModal.styles.js +0 -37
  95. package/dist/components/index.js +0 -118
  96. package/dist/index.d.ts +0 -4
  97. package/dist/index.js +0 -10
  98. package/dist/utils/generateNumbers.js +0 -30
  99. package/dist/utils/getScrollIndex.js +0 -10
  100. package/dist/utils/padWithZero.js +0 -12
  101. /package/dist/{components → typescript/components}/Modal/Modal.styles.d.ts +0 -0
  102. /package/dist/{components → typescript/components}/Modal/index.d.ts +0 -0
  103. /package/dist/{components → typescript/components}/TimerPicker/DurationScroll.d.ts +0 -0
  104. /package/dist/{components → typescript/components}/TimerPicker/TimerPicker.styles.d.ts +0 -0
  105. /package/dist/{components → typescript/components}/TimerPicker/index.d.ts +0 -0
  106. /package/dist/{components → typescript/components}/TimerPickerModal.styles.d.ts +0 -0
  107. /package/dist/{components → typescript/components}/index.d.ts +0 -0
  108. /package/dist/{utils → typescript/utils}/generateNumbers.d.ts +0 -0
  109. /package/dist/{utils → typescript/utils}/getAdjustedLimit.d.ts +0 -0
  110. /package/dist/{utils → typescript/utils}/padWithZero.d.ts +0 -0
@@ -0,0 +1,87 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { StyleSheet } from "react-native";
3
+
4
+ import type { CustomTimerPickerStyles } from "./TimerPicker/TimerPicker.styles";
5
+
6
+ export interface CustomTimerPickerModalStyles extends CustomTimerPickerStyles {
7
+ container?: any;
8
+ contentContainer?: any;
9
+ buttonContainer?: any;
10
+ button?: any;
11
+ cancelButton?: any;
12
+ confirmButton?: any;
13
+ modalTitle?: any;
14
+ }
15
+
16
+ const DARK_MODE_BACKGROUND_COLOR = "#232323";
17
+ const DARK_MODE_TEXT_COLOR = "#E9E9E9";
18
+ const LIGHT_MODE_BACKGROUND_COLOR = "#F1F1F1";
19
+ const LIGHT_MODE_TEXT_COLOR = "#1B1B1B";
20
+
21
+ export const generateStyles = (
22
+ customStyles: CustomTimerPickerModalStyles | undefined
23
+ ) =>
24
+ StyleSheet.create({
25
+ container: {
26
+ justifyContent: "center",
27
+ alignItems: "center",
28
+ overflow: "hidden",
29
+ ...customStyles?.container,
30
+ },
31
+ contentContainer: {
32
+ backgroundColor:
33
+ customStyles?.backgroundColor ?? customStyles?.theme === "dark"
34
+ ? DARK_MODE_BACKGROUND_COLOR
35
+ : LIGHT_MODE_BACKGROUND_COLOR,
36
+ justifyContent: "center",
37
+ alignItems: "center",
38
+ borderRadius: 20,
39
+ padding: 20,
40
+ ...customStyles?.contentContainer,
41
+ },
42
+ buttonContainer: {
43
+ flexDirection: "row",
44
+ marginTop: 25,
45
+ ...customStyles?.buttonContainer,
46
+ },
47
+ button: {
48
+ marginHorizontal: 12,
49
+ paddingVertical: 10,
50
+ paddingHorizontal: 20,
51
+ borderWidth: 1,
52
+ borderRadius: 10,
53
+ fontSize: 16,
54
+ overflow: "hidden",
55
+ ...customStyles?.text,
56
+ ...customStyles?.button,
57
+ },
58
+ cancelButton: {
59
+ borderColor: "gray",
60
+ color:
61
+ customStyles?.theme === "dark" ? DARK_MODE_TEXT_COLOR : "gray",
62
+ backgroundColor:
63
+ customStyles?.theme === "dark" ? "gray" : undefined,
64
+ ...customStyles?.text,
65
+ ...customStyles?.cancelButton,
66
+ },
67
+ confirmButton: {
68
+ borderColor: "green",
69
+ color:
70
+ customStyles?.theme === "dark" ? DARK_MODE_TEXT_COLOR : "green",
71
+ backgroundColor:
72
+ customStyles?.theme === "dark" ? "green" : undefined,
73
+ ...customStyles?.text,
74
+ ...customStyles?.confirmButton,
75
+ },
76
+ modalTitle: {
77
+ fontSize: 24,
78
+ fontWeight: "bold",
79
+ marginBottom: 15,
80
+ color:
81
+ customStyles?.theme === "dark"
82
+ ? DARK_MODE_TEXT_COLOR
83
+ : LIGHT_MODE_TEXT_COLOR,
84
+ ...customStyles?.text,
85
+ ...customStyles?.modalTitle,
86
+ },
87
+ });
@@ -0,0 +1,243 @@
1
+ import React, {
2
+ forwardRef,
3
+ useCallback,
4
+ useImperativeHandle,
5
+ useRef,
6
+ useState,
7
+ } from "react";
8
+ import { View, Text, TouchableOpacity } from "react-native";
9
+
10
+ import TimerPicker, { TimerPickerProps, TimerPickerRef } from "./TimerPicker";
11
+ import Modal from "./Modal";
12
+
13
+ import {
14
+ generateStyles,
15
+ CustomTimerPickerModalStyles,
16
+ } from "./TimerPickerModal.styles";
17
+
18
+ export interface TimerPickerModalRef {
19
+ reset: (options?: { animated?: boolean }) => void;
20
+ setValue: (
21
+ value: {
22
+ hours: number;
23
+ minutes: number;
24
+ seconds: number;
25
+ },
26
+ options?: { animated?: boolean }
27
+ ) => void;
28
+ }
29
+
30
+ export interface TimerPickerModalProps extends TimerPickerProps {
31
+ visible: boolean;
32
+ setIsVisible: (isVisible: boolean) => void;
33
+ onConfirm: ({
34
+ hours,
35
+ minutes,
36
+ seconds,
37
+ }: {
38
+ hours: number;
39
+ minutes: number;
40
+ seconds: number;
41
+ }) => void;
42
+ onCancel?: () => void;
43
+ closeOnOverlayPress?: boolean;
44
+ hideCancelButton?: boolean;
45
+ confirmButtonText?: string;
46
+ cancelButtonText?: string;
47
+ modalTitle?: string;
48
+ modalProps?: React.ComponentProps<typeof Modal>;
49
+ containerProps?: React.ComponentProps<typeof View>;
50
+ contentContainerProps?: React.ComponentProps<typeof View>;
51
+ buttonContainerProps?: React.ComponentProps<typeof View>;
52
+ buttonTouchableOpacityProps?: React.ComponentProps<typeof TouchableOpacity>;
53
+ modalTitleProps?: React.ComponentProps<typeof Text>;
54
+ styles?: CustomTimerPickerModalStyles;
55
+ }
56
+
57
+ const TimerPickerModal = forwardRef<TimerPickerModalRef, TimerPickerModalProps>(
58
+ (
59
+ {
60
+ visible,
61
+ setIsVisible,
62
+ onConfirm,
63
+ onCancel,
64
+ onDurationChange,
65
+ closeOnOverlayPress,
66
+ initialHours = 0,
67
+ initialMinutes = 0,
68
+ initialSeconds = 0,
69
+ hideHours = false,
70
+ hideMinutes = false,
71
+ hideSeconds = false,
72
+ hourLimit,
73
+ minuteLimit,
74
+ secondLimit,
75
+ hourLabel = "h",
76
+ minuteLabel = "m",
77
+ secondLabel = "s",
78
+ padWithNItems = 1,
79
+ disableInfiniteScroll = false,
80
+ hideCancelButton = false,
81
+ confirmButtonText = "Confirm",
82
+ cancelButtonText = "Cancel",
83
+ modalTitle,
84
+ LinearGradient,
85
+ modalProps,
86
+ containerProps,
87
+ contentContainerProps,
88
+ pickerContainerProps,
89
+ buttonContainerProps,
90
+ buttonTouchableOpacityProps,
91
+ modalTitleProps,
92
+ pickerGradientOverlayProps,
93
+ topPickerGradientOverlayProps,
94
+ bottomPickerGradientOverlayProps,
95
+ styles: customStyles,
96
+ },
97
+ ref
98
+ ): React.ReactElement => {
99
+ const styles = generateStyles(customStyles);
100
+
101
+ const [selectedDuration, setSelectedDuration] = useState({
102
+ hours: initialHours,
103
+ minutes: initialMinutes,
104
+ seconds: initialSeconds,
105
+ });
106
+ const [confirmedDuration, setConfirmedDuration] = useState({
107
+ hours: initialHours,
108
+ minutes: initialMinutes,
109
+ seconds: initialSeconds,
110
+ });
111
+
112
+ const hideModal = () => {
113
+ setSelectedDuration({
114
+ hours: confirmedDuration.hours,
115
+ minutes: confirmedDuration.minutes,
116
+ seconds: confirmedDuration.seconds,
117
+ });
118
+ setIsVisible(false);
119
+ };
120
+
121
+ const confirm = () => {
122
+ setConfirmedDuration(selectedDuration);
123
+ onConfirm(selectedDuration);
124
+ };
125
+
126
+ const cancel = () => {
127
+ setIsVisible(false);
128
+ setSelectedDuration(confirmedDuration);
129
+ onCancel?.();
130
+ };
131
+
132
+ // wrapped in useCallback to avoid unnecessary re-renders of TimerPicker
133
+ const durationChange = useCallback(
134
+ (duration: { hours: number; minutes: number; seconds: number }) => {
135
+ setSelectedDuration(duration);
136
+ onDurationChange?.(duration);
137
+ },
138
+ [onDurationChange]
139
+ );
140
+
141
+ const timerPickerRef = useRef<TimerPickerRef>(null);
142
+
143
+ useImperativeHandle(ref, () => ({
144
+ reset: (options) => {
145
+ const initialDuration = {
146
+ hours: initialHours,
147
+ minutes: initialMinutes,
148
+ seconds: initialSeconds,
149
+ };
150
+ setSelectedDuration(initialDuration);
151
+ setConfirmedDuration(initialDuration);
152
+ timerPickerRef.current?.reset(options);
153
+ },
154
+ setValue: (value, options) => {
155
+ setSelectedDuration(value);
156
+ setConfirmedDuration(value);
157
+ timerPickerRef.current?.setValue(value, options);
158
+ },
159
+ }));
160
+
161
+ return (
162
+ <Modal
163
+ isVisible={visible}
164
+ onOverlayPress={closeOnOverlayPress ? hideModal : undefined}
165
+ {...modalProps}
166
+ testID="timer-picker-modal">
167
+ <View {...containerProps} style={styles.container}>
168
+ <View
169
+ {...contentContainerProps}
170
+ style={styles.contentContainer}>
171
+ {modalTitle ? (
172
+ <Text
173
+ {...modalTitleProps}
174
+ style={styles.modalTitle}>
175
+ {modalTitle}
176
+ </Text>
177
+ ) : null}
178
+ <TimerPicker
179
+ ref={timerPickerRef}
180
+ onDurationChange={durationChange}
181
+ initialHours={confirmedDuration.hours}
182
+ initialMinutes={confirmedDuration.minutes}
183
+ initialSeconds={confirmedDuration.seconds}
184
+ hideHours={hideHours}
185
+ hideMinutes={hideMinutes}
186
+ hideSeconds={hideSeconds}
187
+ hourLimit={hourLimit}
188
+ minuteLimit={minuteLimit}
189
+ secondLimit={secondLimit}
190
+ hourLabel={hourLabel}
191
+ minuteLabel={minuteLabel}
192
+ secondLabel={secondLabel}
193
+ padWithNItems={padWithNItems}
194
+ disableInfiniteScroll={disableInfiniteScroll}
195
+ LinearGradient={LinearGradient}
196
+ pickerContainerProps={pickerContainerProps}
197
+ pickerGradientOverlayProps={
198
+ pickerGradientOverlayProps
199
+ }
200
+ topPickerGradientOverlayProps={
201
+ topPickerGradientOverlayProps
202
+ }
203
+ bottomPickerGradientOverlayProps={
204
+ bottomPickerGradientOverlayProps
205
+ }
206
+ styles={customStyles}
207
+ />
208
+ <View
209
+ {...buttonContainerProps}
210
+ style={styles.buttonContainer}>
211
+ {!hideCancelButton ? (
212
+ <TouchableOpacity
213
+ onPress={cancel}
214
+ {...buttonTouchableOpacityProps}>
215
+ <Text
216
+ style={[
217
+ styles.button,
218
+ styles.cancelButton,
219
+ ]}>
220
+ {cancelButtonText}
221
+ </Text>
222
+ </TouchableOpacity>
223
+ ) : null}
224
+ <TouchableOpacity
225
+ onPress={confirm}
226
+ {...buttonTouchableOpacityProps}>
227
+ <Text
228
+ style={[
229
+ styles.button,
230
+ styles.confirmButton,
231
+ ]}>
232
+ {confirmButtonText}
233
+ </Text>
234
+ </TouchableOpacity>
235
+ </View>
236
+ </View>
237
+ </View>
238
+ </Modal>
239
+ );
240
+ }
241
+ );
242
+
243
+ export default React.memo(TimerPickerModal);
package/src/index.ts ADDED
@@ -0,0 +1,14 @@
1
+ export {
2
+ default as TimerPickerModal,
3
+ type TimerPickerModalProps,
4
+ type TimerPickerModalRef,
5
+ } from "./components";
6
+
7
+ export {
8
+ default as TimerPicker,
9
+ type TimerPickerProps,
10
+ type TimerPickerRef,
11
+ } from "./components/TimerPicker";
12
+
13
+ export { type CustomTimerPickerModalStyles } from "./components/TimerPickerModal.styles";
14
+ export { type CustomTimerPickerStyles } from "./components/TimerPicker/TimerPicker.styles";
@@ -0,0 +1,57 @@
1
+ import React from "react";
2
+ import { render } from "@testing-library/react-native";
3
+ import DurationScroll from "../components/TimerPicker/DurationScroll";
4
+
5
+ describe("DurationScroll", () => {
6
+ const onDurationChangeMock = jest.fn();
7
+ const emptyStyles = {
8
+ pickerContainer: {},
9
+ pickerLabelContainer: {},
10
+ pickerLabel: {},
11
+ pickerItemContainer: {},
12
+ pickerItem: {},
13
+ pickerGradientOverlay: {},
14
+ };
15
+
16
+ it("renders without crashing", () => {
17
+ const { getByTestId } = render(
18
+ <DurationScroll
19
+ numberOfItems={1}
20
+ onDurationChange={onDurationChangeMock}
21
+ padWithNItems={0}
22
+ styles={emptyStyles}
23
+ testID="duration-scroll"
24
+ />
25
+ );
26
+ const component = getByTestId("duration-scroll");
27
+ expect(component).toBeDefined();
28
+ });
29
+
30
+ it("renders the correct number of items", () => {
31
+ const { getAllByTestId } = render(
32
+ <DurationScroll
33
+ numberOfItems={2}
34
+ onDurationChange={onDurationChangeMock}
35
+ padWithNItems={1}
36
+ styles={emptyStyles}
37
+ />
38
+ );
39
+ const items = getAllByTestId("picker-item");
40
+ expect(items).toHaveLength(7);
41
+ });
42
+
43
+ it("renders the label if provided", () => {
44
+ const { getByText } = render(
45
+ <DurationScroll
46
+ numberOfItems={59}
47
+ label="Duration"
48
+ onDurationChange={onDurationChangeMock}
49
+ padWithNItems={1}
50
+ styles={emptyStyles}
51
+ />
52
+ );
53
+ const label = getByText("Duration");
54
+ expect(label).toBeDefined();
55
+ });
56
+
57
+ });
@@ -0,0 +1,34 @@
1
+ import React from "react";
2
+ import { Text } from "react-native";
3
+ import { render, fireEvent } from "@testing-library/react-native";
4
+ import Modal from "../components/Modal";
5
+
6
+ describe("Modal", () => {
7
+ it("renders without crashing", () => {
8
+ const { getByTestId } = render(<Modal />);
9
+ const component = getByTestId("modal");
10
+ expect(component).toBeDefined();
11
+ });
12
+
13
+ it("renders children when visible", () => {
14
+ const { getByText } = render(
15
+ <Modal isVisible>
16
+ <Text>{"Modal Content"}</Text>
17
+ </Modal>
18
+ );
19
+ const content = getByText("Modal Content");
20
+ expect(content).toBeDefined();
21
+ });
22
+
23
+ it("calls onOverlayPress when overlay is pressed", () => {
24
+ const onOverlayPressMock = jest.fn();
25
+ const { getByTestId } = render(
26
+ <Modal isVisible onOverlayPress={onOverlayPressMock} />
27
+ );
28
+ const overlay = getByTestId("modal-backdrop");
29
+ fireEvent.press(overlay);
30
+ expect(onOverlayPressMock).toHaveBeenCalled();
31
+ });
32
+
33
+ // Add more test cases to cover different interactions, scenarios, and edge cases
34
+ });
@@ -0,0 +1,27 @@
1
+ import React from "react";
2
+ import { render } from "@testing-library/react-native";
3
+ import TimerPicker from "../components/TimerPicker";
4
+
5
+ describe("TimerPicker", () => {
6
+ it("renders without crashing", () => {
7
+ const { getByTestId } = render(<TimerPicker />);
8
+ const component = getByTestId("timer-picker");
9
+ expect(component).toBeDefined();
10
+ });
11
+
12
+ it("renders without crashing with negative padWithNItems", () => {
13
+ const { getByTestId } = render(<TimerPicker padWithNItems={-1} />);
14
+ const component = getByTestId("timer-picker");
15
+ expect(component).toBeDefined();
16
+ });
17
+
18
+ it("hides minutes and seconds when respective hide props are provided", () => {
19
+ const { queryByTestId } = render(
20
+ <TimerPicker hideMinutes hideSeconds />
21
+ );
22
+ const minutePicker = queryByTestId("duration-scroll-minute");
23
+ const secondPicker = queryByTestId("duration-scroll-second");
24
+ expect(minutePicker).toBeNull();
25
+ expect(secondPicker).toBeNull();
26
+ });
27
+ });
@@ -0,0 +1,70 @@
1
+ import React from "react";
2
+ import { render, fireEvent } from "@testing-library/react-native";
3
+ import TimerPickerModal from "../components";
4
+
5
+ describe("TimerPickerModal", () => {
6
+ const mockOnConfirm = jest.fn();
7
+ const mockOnCancel = jest.fn();
8
+
9
+ const defaultProps = {
10
+ visible: true,
11
+ setIsVisible: jest.fn(),
12
+ onConfirm: mockOnConfirm,
13
+ onCancel: mockOnCancel,
14
+ };
15
+
16
+ it("renders without crashing", () => {
17
+ const { getByTestId } = render(<TimerPickerModal {...defaultProps} />);
18
+ const component = getByTestId("timer-picker-modal");
19
+ expect(component).toBeDefined();
20
+ });
21
+
22
+ it("calls onConfirm when Confirm button is pressed", () => {
23
+ const { getByText } = render(<TimerPickerModal {...defaultProps} />);
24
+ const confirmButton = getByText("Confirm");
25
+ fireEvent.press(confirmButton);
26
+ expect(mockOnConfirm).toHaveBeenCalled();
27
+ });
28
+
29
+ it("calls onCancel when Cancel button is pressed", () => {
30
+ const { getByText } = render(<TimerPickerModal {...defaultProps} />);
31
+ const cancelButton = getByText("Cancel");
32
+ fireEvent.press(cancelButton);
33
+ expect(mockOnCancel).toHaveBeenCalled();
34
+ });
35
+
36
+ it("hides the modal when Cancel button is pressed", () => {
37
+ const setIsVisibleMock = jest.fn();
38
+ const { getByText } = render(
39
+ <TimerPickerModal
40
+ {...defaultProps}
41
+ setIsVisible={setIsVisibleMock}
42
+ />
43
+ );
44
+ const cancelButton = getByText("Cancel");
45
+ fireEvent.press(cancelButton);
46
+ expect(setIsVisibleMock).toHaveBeenCalledWith(false);
47
+ });
48
+
49
+ it("hides the modal when overlay is pressed", () => {
50
+ const setIsVisibleMock = jest.fn();
51
+ const { getByTestId } = render(
52
+ <TimerPickerModal
53
+ {...defaultProps}
54
+ setIsVisible={setIsVisibleMock}
55
+ closeOnOverlayPress
56
+ />
57
+ );
58
+ const overlay = getByTestId("modal-backdrop");
59
+ fireEvent.press(overlay);
60
+ expect(setIsVisibleMock).toHaveBeenCalledWith(false);
61
+ });
62
+
63
+ it("calls onConfirm with selected duration when Confirm button is pressed", () => {
64
+ const { getByText } = render(<TimerPickerModal {...defaultProps} />);
65
+ // Select duration in TimerPicker, assuming its interaction is tested separately
66
+ const confirmButton = getByText("Confirm");
67
+ fireEvent.press(confirmButton);
68
+ expect(mockOnConfirm).toHaveBeenCalledWith(expect.objectContaining({}));
69
+ });
70
+ });
@@ -1,13 +1,11 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.colorToRgba = void 0;
4
- var colorToRgba = function (variables) {
1
+ export const colorToRgba = (variables: { color: string; opacity?: number }) => {
5
2
  // this function is required for expo-linear-gradient on iOS. To fade to transparent, we need
6
3
  // to be able to add opacity to the background color. Supplying 'transparent' does not work
7
4
  // because that is actually a transparent black (rgba(0, 0, 0, 1)), which results in dodgy rendering
8
- var color = variables.color, _a = variables.opacity, opacity = _a === void 0 ? 1 : _a;
5
+
6
+ const { color, opacity = 1 } = variables;
9
7
  // Handle named colors
10
- var namedColors = {
8
+ const namedColors: { [key: string]: string } = {
11
9
  transparent: "rgba(0, 0, 0, 0)",
12
10
  black: "rgba(0, 0, 0, 1)",
13
11
  white: "rgba(255, 255, 255, 1)",
@@ -16,33 +14,36 @@ var colorToRgba = function (variables) {
16
14
  gray: "rgba(128, 128, 128, 1)",
17
15
  red: "rgba(255, 0, 0, 1)",
18
16
  };
17
+
19
18
  if (color in namedColors) {
20
19
  return namedColors[color];
21
20
  }
21
+
22
22
  // Handle RGB format
23
23
  if (color.startsWith("rgb(")) {
24
- var rgbValues = color
24
+ const rgbValues = color
25
25
  .replace("rgb(", "")
26
26
  .replace(")", "")
27
27
  .split(",")
28
- .map(function (value) { return parseInt(value.trim(), 10); });
29
- var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2];
30
- return "rgba(".concat(r, ", ").concat(g, ", ").concat(b, ", ").concat(opacity, ")");
28
+ .map((value) => parseInt(value.trim(), 10));
29
+ const [r, g, b] = rgbValues;
30
+ return `rgba(${r}, ${g}, ${b}, ${opacity})`;
31
31
  }
32
+
32
33
  // Handle hex format
33
34
  if (color.startsWith("#")) {
34
- var hexColor = color.slice(1);
35
+ let hexColor = color.slice(1);
35
36
  if (hexColor.length === 3) {
36
37
  hexColor = hexColor
37
38
  .split("")
38
- .map(function (value) { return value + value; })
39
+ .map((value) => value + value)
39
40
  .join("");
40
41
  }
41
- var r = parseInt(hexColor.slice(0, 2), 16);
42
- var g = parseInt(hexColor.slice(2, 4), 16);
43
- var b = parseInt(hexColor.slice(4, 6), 16);
44
- return "rgba(".concat(r, ", ").concat(g, ", ").concat(b, ", ").concat(opacity, ")");
42
+ const r = parseInt(hexColor.slice(0, 2), 16);
43
+ const g = parseInt(hexColor.slice(2, 4), 16);
44
+ const b = parseInt(hexColor.slice(4, 6), 16);
45
+ return `rgba(${r}, ${g}, ${b}, ${opacity})`;
45
46
  }
47
+
46
48
  return color; // Return unchanged if unable to parse
47
49
  };
48
- exports.colorToRgba = colorToRgba;
@@ -0,0 +1,34 @@
1
+ import { padWithZero } from "./padWithZero";
2
+
3
+ export const generateNumbers = (
4
+ numberOfItems: number,
5
+ options: {
6
+ repeatNTimes?: number;
7
+ padWithZero?: boolean;
8
+ disableInfiniteScroll?: boolean;
9
+ padWithNItems: number;
10
+ }
11
+ ) => {
12
+ if (numberOfItems <= 0) {
13
+ return [];
14
+ }
15
+
16
+ let numbers: string[] = [];
17
+ if (options.padWithZero) {
18
+ for (let i = 0; i <= numberOfItems; i++) {
19
+ numbers.push(padWithZero(i));
20
+ }
21
+ } else {
22
+ for (let i = 0; i <= numberOfItems; i++) {
23
+ numbers.push(String(i));
24
+ }
25
+ }
26
+ if ((options.repeatNTimes ?? 1) > 1) {
27
+ numbers = Array(options.repeatNTimes).fill(numbers).flat();
28
+ }
29
+ if (options.disableInfiniteScroll) {
30
+ numbers.push(...Array(options.padWithNItems).fill(""));
31
+ numbers.unshift(...Array(options.padWithNItems).fill(""));
32
+ }
33
+ return numbers;
34
+ };
@@ -1,18 +1,25 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getAdjustedLimit = void 0;
4
- var getAdjustedLimit = function (limit, numberOfItems) {
1
+ import type { LimitType } from "../components/TimerPicker/DurationScroll";
2
+
3
+ export const getAdjustedLimit = (
4
+ limit: LimitType | undefined,
5
+ numberOfItems: number
6
+ ): {
7
+ max: number;
8
+ min: number;
9
+ } => {
5
10
  if (!limit || (!limit.max && !limit.min)) {
6
11
  return {
7
12
  max: numberOfItems,
8
13
  min: 0,
9
14
  };
10
15
  }
16
+
11
17
  // guard against limits that are out of bounds
12
- var adjustedMaxLimit = limit.max
18
+ const adjustedMaxLimit = limit.max
13
19
  ? Math.min(limit.max, numberOfItems)
14
20
  : numberOfItems;
15
- var adjustedMinLimit = limit.min ? Math.max(limit.min, 0) : 0;
21
+ const adjustedMinLimit = limit.min ? Math.max(limit.min, 0) : 0;
22
+
16
23
  // guard against invalid limits
17
24
  if (adjustedMaxLimit < adjustedMinLimit) {
18
25
  return {
@@ -20,9 +27,9 @@ var getAdjustedLimit = function (limit, numberOfItems) {
20
27
  min: 0,
21
28
  };
22
29
  }
30
+
23
31
  return {
24
32
  max: adjustedMaxLimit,
25
33
  min: adjustedMinLimit,
26
34
  };
27
35
  };
28
- exports.getAdjustedLimit = getAdjustedLimit;