react-native-paper-dates 0.4.6 → 0.7.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 (245) hide show
  1. package/README.md +79 -22
  2. package/lib/commonjs/Date/AnimatedCrossView.js +9 -8
  3. package/lib/commonjs/Date/AnimatedCrossView.js.map +1 -1
  4. package/lib/commonjs/Date/AutoSizer.js +6 -5
  5. package/lib/commonjs/Date/AutoSizer.js.map +1 -1
  6. package/lib/commonjs/Date/Calendar.js +46 -39
  7. package/lib/commonjs/Date/Calendar.js.map +1 -1
  8. package/lib/commonjs/Date/CalendarEdit.js +32 -111
  9. package/lib/commonjs/Date/CalendarEdit.js.map +1 -1
  10. package/lib/commonjs/Date/CalendarHeader.js +23 -12
  11. package/lib/commonjs/Date/CalendarHeader.js.map +1 -1
  12. package/lib/commonjs/Date/DatePickerInput.js +93 -20
  13. package/lib/commonjs/Date/DatePickerInput.js.map +1 -1
  14. package/lib/commonjs/Date/DatePickerModal.js +2 -2
  15. package/lib/commonjs/Date/DatePickerModalContent.js +7 -4
  16. package/lib/commonjs/Date/DatePickerModalContent.js.map +1 -1
  17. package/lib/commonjs/Date/DatePickerModalContentHeader.js +43 -34
  18. package/lib/commonjs/Date/DatePickerModalContentHeader.js.map +1 -1
  19. package/lib/commonjs/Date/DatePickerModalHeader.js +12 -5
  20. package/lib/commonjs/Date/DatePickerModalHeader.js.map +1 -1
  21. package/lib/commonjs/Date/DatePickerModalHeaderBackground.js +6 -5
  22. package/lib/commonjs/Date/DatePickerModalHeaderBackground.js.map +1 -1
  23. package/lib/commonjs/Date/DateRangeInput.js +23 -24
  24. package/lib/commonjs/Date/DateRangeInput.js.map +1 -1
  25. package/lib/commonjs/Date/Day.js +7 -3
  26. package/lib/commonjs/Date/Day.js.map +1 -1
  27. package/lib/commonjs/Date/DayName.js +6 -5
  28. package/lib/commonjs/Date/DayName.js.map +1 -1
  29. package/lib/commonjs/Date/DayNames.js +7 -6
  30. package/lib/commonjs/Date/DayNames.js.map +1 -1
  31. package/lib/commonjs/Date/DayRange.js +9 -8
  32. package/lib/commonjs/Date/DayRange.js.map +1 -1
  33. package/lib/commonjs/Date/Month.js +59 -49
  34. package/lib/commonjs/Date/Month.js.map +1 -1
  35. package/lib/commonjs/Date/Swiper.js +35 -29
  36. package/lib/commonjs/Date/Swiper.js.map +1 -1
  37. package/lib/commonjs/Date/Swiper.native.js +29 -23
  38. package/lib/commonjs/Date/Swiper.native.js.map +1 -1
  39. package/lib/commonjs/Date/SwiperUtils.js +7 -6
  40. package/lib/commonjs/Date/SwiperUtils.js.map +1 -1
  41. package/lib/commonjs/Date/YearPicker.js +30 -20
  42. package/lib/commonjs/Date/YearPicker.js.map +1 -1
  43. package/lib/commonjs/Date/dateUtils.js +106 -37
  44. package/lib/commonjs/Date/dateUtils.js.map +1 -1
  45. package/lib/commonjs/Date/inputUtils.js +84 -0
  46. package/lib/commonjs/Date/inputUtils.js.map +1 -0
  47. package/lib/commonjs/TextInputMask.js +11 -10
  48. package/lib/commonjs/TextInputMask.js.map +1 -1
  49. package/lib/commonjs/Time/AmPmSwitcher.js +37 -19
  50. package/lib/commonjs/Time/AmPmSwitcher.js.map +1 -1
  51. package/lib/commonjs/Time/AnalogClock.js +25 -15
  52. package/lib/commonjs/Time/AnalogClock.js.map +1 -1
  53. package/lib/commonjs/Time/AnalogClockHours.js +17 -11
  54. package/lib/commonjs/Time/AnalogClockHours.js.map +1 -1
  55. package/lib/commonjs/Time/AnalogClockMinutes.js +7 -6
  56. package/lib/commonjs/Time/AnalogClockMinutes.js.map +1 -1
  57. package/lib/commonjs/Time/AnimatedClockSwitcher.js +8 -7
  58. package/lib/commonjs/Time/AnimatedClockSwitcher.js.map +1 -1
  59. package/lib/commonjs/Time/TimeInput.js +16 -12
  60. package/lib/commonjs/Time/TimeInput.js.map +1 -1
  61. package/lib/commonjs/Time/TimeInputs.js +12 -11
  62. package/lib/commonjs/Time/TimeInputs.js.map +1 -1
  63. package/lib/commonjs/Time/TimePicker.js +37 -15
  64. package/lib/commonjs/Time/TimePicker.js.map +1 -1
  65. package/lib/commonjs/Time/TimePickerModal.js +19 -15
  66. package/lib/commonjs/Time/TimePickerModal.js.map +1 -1
  67. package/lib/commonjs/Time/timeUtils.js +14 -9
  68. package/lib/commonjs/Time/timeUtils.js.map +1 -1
  69. package/lib/commonjs/index.js +66 -5
  70. package/lib/commonjs/index.js.map +1 -1
  71. package/lib/commonjs/translations/en.js +25 -0
  72. package/lib/commonjs/translations/en.js.map +1 -0
  73. package/lib/commonjs/translations/enGB.js +25 -0
  74. package/lib/commonjs/translations/enGB.js.map +1 -0
  75. package/lib/commonjs/translations/nl.js +25 -0
  76. package/lib/commonjs/translations/nl.js.map +1 -0
  77. package/lib/commonjs/translations/pl.js +25 -0
  78. package/lib/commonjs/translations/pl.js.map +1 -0
  79. package/lib/commonjs/translations/utils.js +31 -0
  80. package/lib/commonjs/translations/utils.js.map +1 -0
  81. package/lib/commonjs/utils.js +19 -9
  82. package/lib/commonjs/utils.js.map +1 -1
  83. package/lib/module/Date/AnimatedCrossView.js +7 -6
  84. package/lib/module/Date/AnimatedCrossView.js.map +1 -1
  85. package/lib/module/Date/AutoSizer.js +4 -3
  86. package/lib/module/Date/AutoSizer.js.map +1 -1
  87. package/lib/module/Date/Calendar.js +46 -39
  88. package/lib/module/Date/Calendar.js.map +1 -1
  89. package/lib/module/Date/CalendarEdit.js +28 -104
  90. package/lib/module/Date/CalendarEdit.js.map +1 -1
  91. package/lib/module/Date/CalendarHeader.js +19 -9
  92. package/lib/module/Date/CalendarHeader.js.map +1 -1
  93. package/lib/module/Date/DatePickerInput.js +88 -18
  94. package/lib/module/Date/DatePickerInput.js.map +1 -1
  95. package/lib/module/Date/DatePickerModalContent.js +5 -2
  96. package/lib/module/Date/DatePickerModalContent.js.map +1 -1
  97. package/lib/module/Date/DatePickerModalContentHeader.js +38 -30
  98. package/lib/module/Date/DatePickerModalContentHeader.js.map +1 -1
  99. package/lib/module/Date/DatePickerModalHeader.js +9 -3
  100. package/lib/module/Date/DatePickerModalHeader.js.map +1 -1
  101. package/lib/module/Date/DatePickerModalHeaderBackground.js +4 -3
  102. package/lib/module/Date/DatePickerModalHeaderBackground.js.map +1 -1
  103. package/lib/module/Date/DateRangeInput.js +22 -22
  104. package/lib/module/Date/DateRangeInput.js.map +1 -1
  105. package/lib/module/Date/Day.js +5 -1
  106. package/lib/module/Date/Day.js.map +1 -1
  107. package/lib/module/Date/DayName.js +4 -3
  108. package/lib/module/Date/DayName.js.map +1 -1
  109. package/lib/module/Date/DayNames.js +5 -4
  110. package/lib/module/Date/DayNames.js.map +1 -1
  111. package/lib/module/Date/DayRange.js +7 -6
  112. package/lib/module/Date/DayRange.js.map +1 -1
  113. package/lib/module/Date/Month.js +54 -45
  114. package/lib/module/Date/Month.js.map +1 -1
  115. package/lib/module/Date/Swiper.js +32 -26
  116. package/lib/module/Date/Swiper.js.map +1 -1
  117. package/lib/module/Date/Swiper.native.js +27 -21
  118. package/lib/module/Date/Swiper.native.js.map +1 -1
  119. package/lib/module/Date/SwiperUtils.js +5 -4
  120. package/lib/module/Date/SwiperUtils.js.map +1 -1
  121. package/lib/module/Date/YearPicker.js +28 -18
  122. package/lib/module/Date/YearPicker.js.map +1 -1
  123. package/lib/module/Date/dateUtils.js +78 -29
  124. package/lib/module/Date/dateUtils.js.map +1 -1
  125. package/lib/module/Date/inputUtils.js +70 -0
  126. package/lib/module/Date/inputUtils.js.map +1 -0
  127. package/lib/module/TextInputMask.js +9 -8
  128. package/lib/module/TextInputMask.js.map +1 -1
  129. package/lib/module/Time/AmPmSwitcher.js +35 -18
  130. package/lib/module/Time/AmPmSwitcher.js.map +1 -1
  131. package/lib/module/Time/AnalogClock.js +23 -14
  132. package/lib/module/Time/AnalogClock.js.map +1 -1
  133. package/lib/module/Time/AnalogClockHours.js +14 -9
  134. package/lib/module/Time/AnalogClockHours.js.map +1 -1
  135. package/lib/module/Time/AnalogClockMinutes.js +5 -4
  136. package/lib/module/Time/AnalogClockMinutes.js.map +1 -1
  137. package/lib/module/Time/AnimatedClockSwitcher.js +6 -5
  138. package/lib/module/Time/AnimatedClockSwitcher.js.map +1 -1
  139. package/lib/module/Time/TimeInput.js +14 -10
  140. package/lib/module/Time/TimeInput.js.map +1 -1
  141. package/lib/module/Time/TimeInputs.js +10 -9
  142. package/lib/module/Time/TimeInputs.js.map +1 -1
  143. package/lib/module/Time/TimePicker.js +32 -12
  144. package/lib/module/Time/TimePicker.js.map +1 -1
  145. package/lib/module/Time/TimePickerModal.js +17 -13
  146. package/lib/module/Time/TimePickerModal.js.map +1 -1
  147. package/lib/module/Time/timeUtils.js +5 -1
  148. package/lib/module/Time/timeUtils.js.map +1 -1
  149. package/lib/module/index.js +6 -0
  150. package/lib/module/index.js.map +1 -1
  151. package/lib/module/translations/en.js +18 -0
  152. package/lib/module/translations/en.js.map +1 -0
  153. package/lib/module/translations/enGB.js +18 -0
  154. package/lib/module/translations/enGB.js.map +1 -0
  155. package/lib/module/translations/nl.js +18 -0
  156. package/lib/module/translations/nl.js.map +1 -0
  157. package/lib/module/translations/pl.js +18 -0
  158. package/lib/module/translations/pl.js.map +1 -0
  159. package/lib/module/translations/utils.js +22 -0
  160. package/lib/module/translations/utils.js.map +1 -0
  161. package/lib/module/utils.js +11 -5
  162. package/lib/module/utils.js.map +1 -1
  163. package/lib/typescript/{src/Date → Date}/AnimatedCrossView.d.ts +0 -0
  164. package/lib/typescript/{src/Date → Date}/AutoSizer.d.ts +0 -0
  165. package/lib/typescript/{src/Date → Date}/Calendar.d.ts +5 -3
  166. package/lib/typescript/{src/Date → Date}/CalendarEdit.d.ts +3 -3
  167. package/lib/typescript/{src/Date → Date}/CalendarHeader.d.ts +1 -1
  168. package/lib/typescript/Date/DatePickerInput.d.ts +18 -0
  169. package/lib/typescript/{src/Date → Date}/DatePickerModal.d.ts +0 -0
  170. package/lib/typescript/{src/Date → Date}/DatePickerModalContent.d.ts +2 -1
  171. package/lib/typescript/{src/Date → Date}/DatePickerModalContentHeader.d.ts +4 -4
  172. package/lib/typescript/{src/Date → Date}/DatePickerModalHeader.d.ts +1 -0
  173. package/lib/typescript/{src/Date → Date}/DatePickerModalHeaderBackground.d.ts +0 -0
  174. package/lib/typescript/Date/DateRangeInput.d.ts +3 -0
  175. package/lib/typescript/{src/Date → Date}/Day.d.ts +0 -0
  176. package/lib/typescript/{src/Date → Date}/DayName.d.ts +0 -0
  177. package/lib/typescript/{src/Date → Date}/DayNames.d.ts +0 -0
  178. package/lib/typescript/{src/Date → Date}/DayRange.d.ts +0 -0
  179. package/lib/typescript/{src/Date → Date}/Month.d.ts +0 -0
  180. package/lib/typescript/{src/Date → Date}/Swiper.d.ts +0 -0
  181. package/lib/typescript/{src/Date → Date}/Swiper.native.d.ts +0 -0
  182. package/lib/typescript/{src/Date → Date}/SwiperUtils.d.ts +1 -1
  183. package/lib/typescript/{src/Date → Date}/Week.d.ts +0 -0
  184. package/lib/typescript/{src/Date → Date}/YearPicker.d.ts +0 -0
  185. package/lib/typescript/{src/Date → Date}/dateUtils.d.ts +15 -0
  186. package/lib/typescript/{src/Date → Date}/dateUtils.test.d.ts +0 -0
  187. package/lib/typescript/Date/inputUtils.d.ts +14 -0
  188. package/lib/typescript/TextInputMask.d.ts +11 -0
  189. package/lib/typescript/Time/AmPmSwitcher.d.ts +4 -0
  190. package/lib/typescript/{src/Time → Time}/AnalogClock.d.ts +1 -1
  191. package/lib/typescript/{src/Time → Time}/AnalogClockHours.d.ts +0 -0
  192. package/lib/typescript/{src/Time → Time}/AnalogClockMinutes.d.ts +0 -0
  193. package/lib/typescript/{src/Time → Time}/AnimatedClockSwitcher.d.ts +0 -0
  194. package/lib/typescript/{src/Time → Time}/TimeInput.d.ts +0 -0
  195. package/lib/typescript/{src/Time → Time}/TimeInputs.d.ts +1 -1
  196. package/lib/typescript/{src/Time → Time}/TimePicker.d.ts +4 -0
  197. package/lib/typescript/{src/Time → Time}/TimePickerModal.d.ts +1 -1
  198. package/lib/typescript/{src/Time → Time}/timeUtils.d.ts +0 -0
  199. package/lib/typescript/index.d.ts +13 -0
  200. package/lib/typescript/translations/en.d.ts +3 -0
  201. package/lib/typescript/translations/enGB.d.ts +3 -0
  202. package/lib/typescript/translations/nl.d.ts +3 -0
  203. package/lib/typescript/translations/pl.d.ts +3 -0
  204. package/lib/typescript/translations/utils.d.ts +18 -0
  205. package/lib/typescript/utils.d.ts +58 -0
  206. package/package.json +39 -38
  207. package/src/.DS_Store +0 -0
  208. package/src/Date/Calendar.tsx +14 -13
  209. package/src/Date/CalendarEdit.tsx +17 -121
  210. package/src/Date/CalendarHeader.tsx +18 -3
  211. package/src/Date/DatePickerInput.tsx +103 -25
  212. package/src/Date/DatePickerModalContent.tsx +5 -1
  213. package/src/Date/DatePickerModalContentHeader.tsx +26 -12
  214. package/src/Date/DatePickerModalHeader.tsx +8 -1
  215. package/src/Date/DateRangeInput.tsx +26 -17
  216. package/src/Date/Day.tsx +4 -0
  217. package/src/Date/Month.tsx +20 -44
  218. package/src/Date/Swiper.tsx +1 -0
  219. package/src/Date/SwiperUtils.ts +1 -1
  220. package/src/Date/YearPicker.tsx +6 -1
  221. package/src/Date/dateUtils.tsx +70 -9
  222. package/src/Date/inputUtils.ts +94 -0
  223. package/src/TextInputMask.tsx +10 -3
  224. package/src/Time/AmPmSwitcher.tsx +20 -11
  225. package/src/Time/AnalogClock.tsx +12 -14
  226. package/src/Time/AnalogClockHours.tsx +14 -5
  227. package/src/Time/AnalogClockMinutes.tsx +4 -1
  228. package/src/Time/TimeInput.tsx +3 -0
  229. package/src/Time/TimeInputs.tsx +1 -5
  230. package/src/Time/TimePicker.tsx +44 -22
  231. package/src/Time/TimePickerModal.tsx +4 -1
  232. package/src/Time/timeUtils.ts +4 -1
  233. package/src/index.tsx +7 -0
  234. package/src/translations/en.ts +20 -0
  235. package/src/translations/enGB.ts +20 -0
  236. package/src/translations/nl.ts +20 -0
  237. package/src/translations/pl.ts +21 -0
  238. package/src/translations/utils.ts +47 -0
  239. package/src/utils.ts +13 -5
  240. package/lib/typescript/src/Date/DatePickerInput.d.ts +0 -1
  241. package/lib/typescript/src/Date/DateRangeInput.d.ts +0 -1
  242. package/lib/typescript/src/TextInputMask.d.ts +0 -3
  243. package/lib/typescript/src/Time/AmPmSwitcher.d.ts +0 -4
  244. package/lib/typescript/src/index.d.ts +0 -6
  245. package/lib/typescript/src/utils.d.ts +0 -7
@@ -18,8 +18,7 @@ import {
18
18
  startAtIndex,
19
19
  beginOffset,
20
20
  estimatedMonthHeight,
21
- isDateWithinOptionalRange,
22
- dateToUnix,
21
+ useRangeChecker,
23
22
  } from './dateUtils'
24
23
  import { getCalendarHeaderHeight } from './CalendarHeader'
25
24
  import type {
@@ -91,35 +90,7 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
91
90
  const textColorOnPrimary = useTextColorOnPrimary()
92
91
  const realIndex = getRealIndex(index)
93
92
  const isHorizontal = scrollMode === 'horizontal'
94
-
95
- const validRangeStart =
96
- validRange?.startDate instanceof Date
97
- ? dateToUnix(
98
- new Date(
99
- validRange?.startDate.getFullYear(),
100
- validRange?.startDate.getMonth(),
101
- validRange?.startDate.getDate(),
102
- 0,
103
- 0,
104
- 0
105
- )
106
- )
107
- : undefined
108
-
109
- const validRangeEnd =
110
- validRange?.endDate instanceof Date
111
- ? dateToUnix(
112
- new Date(
113
- validRange?.endDate.getFullYear(),
114
- validRange?.endDate.getMonth(),
115
- validRange?.endDate.getDate(),
116
- 23,
117
- 59,
118
- 59
119
- )
120
- )
121
- : undefined
122
-
93
+ const { isDisabled, isWithinValidRange } = useRangeChecker(validRange)
123
94
  const { monthName, month, year } = React.useMemo(() => {
124
95
  const md = addMonths(new Date(), realIndex)
125
96
  const y = md.getFullYear()
@@ -151,13 +122,15 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
151
122
  const isToday = areDatesOnSameDay(day, today)
152
123
 
153
124
  let inRange = false
154
- let disabled = false
125
+ let disabled = isDisabled(day)
155
126
  let selected = false
127
+
156
128
  let leftCrop = dayOfMonth === 1
157
129
  let rightCrop = dayOfMonth === daysInMonth
158
130
 
159
131
  const isFirstDayOfMonth = dayOfMonth === 1
160
132
  const isLastDayOfMonth = dayOfMonth === daysInMonth
133
+
161
134
  if (mode === 'range') {
162
135
  const selectedStartDay = areDatesOnSameDay(day, startDate)
163
136
  const selectedEndDay = areDatesOnSameDay(day, endDate)
@@ -226,18 +199,13 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
226
199
  selected = false
227
200
  }
228
201
  }
229
-
230
- //
231
202
  } else if (mode === 'single') {
232
203
  selected = areDatesOnSameDay(day, date)
233
204
  }
234
- //
235
- const isWithinOptionalValidRange = isDateWithinOptionalRange(day, {
236
- startUnix: validRangeStart,
237
- endUnix: validRangeEnd,
238
- })
239
205
 
240
- if (inRange) {
206
+ const isWithinOptionalValidRange = isWithinValidRange(day)
207
+
208
+ if (inRange && !disabled) {
241
209
  disabled = false
242
210
  }
243
211
 
@@ -267,13 +235,13 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
267
235
  year,
268
236
  month,
269
237
  index,
238
+ isDisabled,
239
+ mode,
240
+ isWithinValidRange,
270
241
  startDate,
271
242
  endDate,
272
- date,
273
243
  dates,
274
- validRangeStart,
275
- validRangeEnd,
276
- mode,
244
+ date,
277
245
  ])
278
246
 
279
247
  return (
@@ -292,12 +260,17 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
292
260
  <TouchableRipple
293
261
  disabled={!isHorizontal}
294
262
  onPress={isHorizontal ? () => onPressYear(year) : undefined}
263
+ accessibilityRole="button"
264
+ accessibilityLabel={`${monthName} ${year}`}
295
265
  style={[
296
266
  styles.yearButton,
297
267
  {
298
268
  borderRadius: roundness,
299
269
  },
300
270
  ]}
271
+ // RN types bug
272
+ hasTVPreferredFocus={undefined}
273
+ tvParallaxProperties={undefined}
301
274
  >
302
275
  <View
303
276
  style={[
@@ -317,6 +290,9 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
317
290
  <IconButton
318
291
  onPress={isHorizontal ? () => onPressYear(year) : undefined}
319
292
  icon={selectingYear ? 'chevron-up' : 'chevron-down'}
293
+ // RN types bug
294
+ hasTVPreferredFocus={undefined}
295
+ tvParallaxProperties={undefined}
320
296
  />
321
297
  </View>
322
298
  </View>
@@ -94,6 +94,7 @@ function VerticalScroller({
94
94
  const [visibleIndexes, setVisibleIndexes] = React.useState<number[]>(
95
95
  visibleArray(initialIndex)
96
96
  )
97
+ // eslint-disable-next-line no-undef
97
98
  const parentRef = React.useRef<HTMLDivElement | null>(null)
98
99
 
99
100
  useIsomorphicLayoutEffect(() => {
@@ -1,4 +1,4 @@
1
- import { MutableRefObject } from 'react'
1
+ import type { MutableRefObject } from 'react'
2
2
  import { useLatest } from '../utils'
3
3
  import * as React from 'react'
4
4
  import {
@@ -67,14 +67,19 @@ function YearPure({
67
67
  }: {
68
68
  year: number
69
69
  selected: boolean
70
- onPressYear: (year: number) => any
70
+ onPressYear: (newYear: number) => any
71
71
  }) {
72
72
  const theme = useTheme()
73
73
  return (
74
74
  <View style={styles.year}>
75
75
  <TouchableRipple
76
76
  onPress={() => onPressYear(year)}
77
+ accessibilityRole="button"
78
+ accessibilityLabel={String(year)}
77
79
  style={styles.yearButton}
80
+ // RN types bug
81
+ hasTVPreferredFocus={undefined}
82
+ tvParallaxProperties={undefined}
78
83
  >
79
84
  <View
80
85
  style={[
@@ -1,3 +1,7 @@
1
+ import * as React from 'react'
2
+ import { useLatest } from '../utils'
3
+ import type { ValidRangeType } from './Calendar'
4
+
1
5
  export type DisableWeekDaysType = number[]
2
6
 
3
7
  export function showWeekDay(
@@ -61,15 +65,42 @@ export function getFirstDayOfMonth({
61
65
  return new Date(year, month, 1).getDay()
62
66
  }
63
67
 
64
- // export function getLastDayOfMonth({
65
- // year,
66
- // month,
67
- // }: {
68
- // year: number
69
- // month: number
70
- // }): number {
71
- // return new Date(year, month, getDaysInMonth({ year, month })).getDay()
72
- // }
68
+ export function useRangeChecker(validRange: ValidRangeType | undefined) {
69
+ const validStart = validRange?.startDate
70
+ const validEnd = validRange?.endDate
71
+ const startUnix =
72
+ validStart instanceof Date
73
+ ? dateToUnix(getStartOfDay(validStart))
74
+ : undefined
75
+
76
+ const endUnix =
77
+ validEnd instanceof Date ? dateToUnix(getEndOfDay(validEnd)) : undefined
78
+
79
+ const validDisabledDatesRef = useLatest(validRange?.disabledDates)
80
+
81
+ const isWithinValidRange = React.useCallback(
82
+ (day: Date) => {
83
+ return isDateWithinOptionalRange(day, {
84
+ startUnix: startUnix,
85
+ endUnix: endUnix,
86
+ })
87
+ },
88
+ [startUnix, endUnix]
89
+ )
90
+
91
+ const isDisabled = React.useCallback(
92
+ (day: Date) => {
93
+ return validDisabledDatesRef.current
94
+ ? validDisabledDatesRef.current.some((disabledDate) =>
95
+ areDatesOnSameDay(disabledDate, day)
96
+ )
97
+ : false
98
+ },
99
+ [validDisabledDatesRef]
100
+ )
101
+
102
+ return { isDisabled, isWithinValidRange, validStart, validEnd }
103
+ }
73
104
 
74
105
  export function areDatesOnSameDay(a: Date, b?: Date | null | undefined) {
75
106
  if (!b) {
@@ -170,6 +201,36 @@ export function getInitialIndex(date: Date | undefined) {
170
201
  return startAtIndex + months
171
202
  }
172
203
 
204
+ export function useInputFormatter({ locale }: { locale: string | undefined }) {
205
+ return React.useMemo(() => {
206
+ return new Intl.DateTimeFormat(locale, {
207
+ month: '2-digit',
208
+ day: '2-digit',
209
+ year: 'numeric',
210
+ })
211
+ }, [locale])
212
+ }
213
+ export function getStartOfDay(d: Date): Date {
214
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0)
215
+ }
216
+ export function getEndOfDay(d: Date): Date {
217
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate(), 23, 59, 59)
218
+ }
219
+ export function useInputFormat({
220
+ formatter,
221
+ }: {
222
+ formatter: Intl.DateTimeFormat
223
+ }) {
224
+ return React.useMemo(() => {
225
+ // TODO: something cleaner and more universal?
226
+ const inputDate = formatter.format(new Date(2020, 10 - 1, 1))
227
+ return inputDate
228
+ .replace('2020', 'YYYY')
229
+ .replace('10', 'MM')
230
+ .replace('01', 'DD')
231
+ }, [formatter])
232
+ }
233
+
173
234
  export function differenceInMonths(firstDate: Date, secondDate: Date) {
174
235
  let diffMonths = (secondDate.getFullYear() - firstDate.getFullYear()) * 12
175
236
  diffMonths -= firstDate.getMonth()
@@ -0,0 +1,94 @@
1
+ import { useInputFormat, useInputFormatter, useRangeChecker } from './dateUtils'
2
+ import * as React from 'react'
3
+ import type { ValidRangeType } from './Calendar'
4
+ import { getTranslation } from 'react-native-paper-dates'
5
+
6
+ export default function useDateInput({
7
+ locale,
8
+ value,
9
+ validRange,
10
+ inputMode,
11
+ onChange,
12
+ }: {
13
+ onChange: (d: Date) => void
14
+ locale: undefined | string
15
+ value: Date | undefined
16
+ validRange: ValidRangeType | undefined
17
+ inputMode: 'start' | 'end'
18
+ }) {
19
+ const { isDisabled, isWithinValidRange, validStart, validEnd } =
20
+ useRangeChecker(validRange)
21
+ const [error, setError] = React.useState<null | string>(null)
22
+ const formatter = useInputFormatter({ locale })
23
+ const inputFormat = useInputFormat({ formatter })
24
+ const formattedValue = formatter.format(value)
25
+ const onChangeText = (date: string) => {
26
+ const dayIndex = inputFormat.indexOf('DD')
27
+ const monthIndex = inputFormat.indexOf('MM')
28
+ const yearIndex = inputFormat.indexOf('YYYY')
29
+
30
+ const day = Number(date.slice(dayIndex, dayIndex + 2))
31
+ const year = Number(date.slice(yearIndex, yearIndex + 4))
32
+ const month = Number(date.slice(monthIndex, monthIndex + 2))
33
+
34
+ if (Number.isNaN(day) || Number.isNaN(year) || Number.isNaN(month)) {
35
+ setError(
36
+ getTranslation(
37
+ locale,
38
+ 'notAccordingToDateFormat',
39
+ () => 'notAccordingToDateFormat'
40
+ )(inputFormat)
41
+ )
42
+ return
43
+ }
44
+
45
+ const finalDate =
46
+ inputMode === 'end'
47
+ ? new Date(year, month - 1, day, 23, 59, 59)
48
+ : new Date(year, month - 1, day)
49
+
50
+ if (isDisabled(finalDate)) {
51
+ setError(getTranslation(locale, 'dateIsDisabled'))
52
+ return
53
+ }
54
+ if (!isWithinValidRange(finalDate)) {
55
+ let errors =
56
+ validStart && validEnd
57
+ ? [
58
+ `${getTranslation(locale, 'mustBeBetween')} ${formatter.format(
59
+ validStart
60
+ )} - ${formatter.format(validEnd)}`,
61
+ ]
62
+ : [
63
+ validStart
64
+ ? `${getTranslation(
65
+ locale,
66
+ 'mustBeHigherThan'
67
+ )} ${formatter.format(validStart)}`
68
+ : '',
69
+ validEnd
70
+ ? `${getTranslation(
71
+ locale,
72
+ 'mustBeLowerThan'
73
+ )} ${formatter.format(validEnd)}`
74
+ : '',
75
+ ]
76
+ setError(errors.filter((n) => n).join(' '))
77
+ return
78
+ }
79
+
80
+ setError(null)
81
+ if (inputMode === 'end') {
82
+ onChange(finalDate)
83
+ } else {
84
+ onChange(finalDate)
85
+ }
86
+ }
87
+ return {
88
+ onChange,
89
+ error,
90
+ formattedValue,
91
+ onChangeText,
92
+ inputFormat,
93
+ }
94
+ }
@@ -67,10 +67,17 @@ function enhanceTextWithMask(
67
67
  }
68
68
 
69
69
  function TextInputWithMask(
70
- { onChangeText, value, mask, ...rest }: any,
70
+ {
71
+ onChangeText,
72
+ value,
73
+ mask,
74
+ ...rest
75
+ }: React.ComponentProps<typeof TextInput> & { mask: string },
71
76
  ref: any
72
77
  ) {
73
- const [controlledValue, setControlledValue] = React.useState<string>(value)
78
+ const [controlledValue, setControlledValue] = React.useState<string>(
79
+ value || ''
80
+ )
74
81
 
75
82
  const onInnerChange = (text: string) => {
76
83
  const enhancedText = enhanceTextWithMask(text, mask, controlledValue)
@@ -82,7 +89,7 @@ function TextInputWithMask(
82
89
  }
83
90
 
84
91
  React.useEffect(() => {
85
- setControlledValue(value)
92
+ setControlledValue(value || '')
86
93
  }, [value])
87
94
 
88
95
  return (
@@ -3,15 +3,17 @@ import { View, StyleSheet } from 'react-native'
3
3
  import { Text, TouchableRipple, useTheme } from 'react-native-paper'
4
4
  import { useMemo } from 'react'
5
5
  import Color from 'color'
6
- import { getHourType, hourTypes, useSwitchColors } from './timeUtils'
6
+ import { useSwitchColors } from './timeUtils'
7
+ import { DisplayModeContext } from './TimePicker'
7
8
 
8
9
  export default function AmPmSwitcher({
9
- hours,
10
10
  onChange,
11
+ hours,
11
12
  }: {
12
13
  hours: number
13
- onChange: (hours: number) => any
14
+ onChange: (newHours: number) => any
14
15
  }) {
16
+ const { setMode, mode } = React.useContext(DisplayModeContext)
15
17
  const theme = useTheme()
16
18
  const backgroundColor = useMemo<string>(() => {
17
19
  if (theme.dark) {
@@ -20,10 +22,7 @@ export default function AmPmSwitcher({
20
22
  return Color(theme.colors.surface).darken(0.1).hex()
21
23
  }, [theme])
22
24
 
23
- const hourType = getHourType(hours)
24
- const isAM = hourType === hourTypes.am
25
- const isPM = hourType === hourTypes.pm
26
-
25
+ const isAM = mode === 'AM'
27
26
  return (
28
27
  <View
29
28
  style={[
@@ -36,16 +35,26 @@ export default function AmPmSwitcher({
36
35
  >
37
36
  <SwitchButton
38
37
  label="AM"
39
- onPress={isAM ? undefined : () => onChange(hours - 12)}
38
+ onPress={() => {
39
+ setMode('AM')
40
+ if (hours - 12 >= 0) {
41
+ onChange(hours - 12)
42
+ }
43
+ }}
40
44
  selected={isAM}
41
45
  disabled={isAM}
42
46
  />
43
47
  <View style={[styles.switchSeparator, { backgroundColor }]} />
44
48
  <SwitchButton
45
49
  label="PM"
46
- onPress={isPM ? undefined : () => onChange(hours + 12)}
47
- selected={isPM}
48
- disabled={isPM}
50
+ onPress={() => {
51
+ setMode('PM')
52
+ if (hours + 12 <= 24) {
53
+ onChange(hours + 12)
54
+ }
55
+ }}
56
+ selected={!isAM}
57
+ disabled={!isAM}
49
58
  />
50
59
  </View>
51
60
  )
@@ -12,9 +12,7 @@ import {
12
12
  getAngle,
13
13
  getHours,
14
14
  getHourType,
15
- getHourTypeFromOffset,
16
15
  getMinutes,
17
- hourTypes,
18
16
  PossibleClockTypes,
19
17
  } from './timeUtils'
20
18
  import * as React from 'react'
@@ -24,6 +22,7 @@ import AnalogClockHours from './AnalogClockHours'
24
22
 
25
23
  import AnimatedClockSwitcher from './AnimatedClockSwitcher'
26
24
  import AnalogClockMinutes from './AnalogClockMinutes'
25
+ import { DisplayModeContext } from './TimePicker'
27
26
 
28
27
  function AnalogClock({
29
28
  hours,
@@ -36,18 +35,14 @@ function AnalogClock({
36
35
  minutes: number
37
36
  focused: PossibleClockTypes
38
37
  is24Hour: boolean
39
- onChange: ({
40
- hours,
41
- minutes,
42
- focused,
43
- }: {
38
+ onChange: (hoursMinutesAndFocused: {
44
39
  hours: number
45
40
  minutes: number
46
41
  focused?: undefined | PossibleClockTypes
47
42
  }) => any
48
43
  }) {
49
44
  const theme = useTheme()
50
-
45
+ const { mode } = React.useContext(DisplayModeContext)
51
46
  // used to make pointer shorter if hours are selected and above 12
52
47
  const shortPointer = (hours === 0 || hours > 12) && is24Hour
53
48
 
@@ -60,6 +55,7 @@ function AnalogClock({
60
55
  const minutesRef = useLatest(minutes)
61
56
  const focusedRef = useLatest(focused)
62
57
  const is24HourRef = useLatest(is24Hour)
58
+ const modeRef = useLatest(mode)
63
59
 
64
60
  const onPointerMove = React.useCallback(
65
61
  (e: GestureResponderEvent, final: boolean) => {
@@ -73,14 +69,16 @@ function AnalogClock({
73
69
  let previousHourType = getHourType(hoursRef.current)
74
70
  let pickedHours = getHours(angle, previousHourType)
75
71
 
76
- let hourTypeFromOffset = getHourTypeFromOffset(x, y, circleSize)
77
- let hours24AndPM = hours24 && hourTypeFromOffset === hourTypes.pm
78
- let hours12AndPm = !hours24 && previousHourType === hourTypes.pm
72
+ let hours12AndPm = !hours24 && modeRef.current === 'PM'
79
73
 
80
- // TODO: check which mode is switched on am/pm
81
- if (hours12AndPm || hours24AndPM) {
74
+ // Avoiding the "24h"
75
+ // Should be 12h for 12 hours and PM mode
76
+ if ((hours12AndPm || hours24) && pickedHours + 12 < 24) {
82
77
  pickedHours += 12
83
78
  }
79
+ if (modeRef.current === 'AM' && pickedHours === 12) {
80
+ pickedHours = 0
81
+ }
84
82
 
85
83
  if (pickedHours === 24) {
86
84
  pickedHours = 0
@@ -103,7 +101,7 @@ function AnalogClock({
103
101
  }
104
102
  }
105
103
  },
106
- [focusedRef, is24HourRef, hoursRef, onChangeRef, minutesRef]
104
+ [focusedRef, is24HourRef, hoursRef, onChangeRef, minutesRef, modeRef]
107
105
  )
108
106
 
109
107
  const panResponder = React.useRef(
@@ -3,6 +3,7 @@ import { View, StyleSheet } from 'react-native'
3
3
  import { Text } from 'react-native-paper'
4
4
  import { circleSize } from './timeUtils'
5
5
  import { useTextColorOnPrimary } from '../utils'
6
+ import { DisplayModeContext } from './TimePicker'
6
7
 
7
8
  function AnalogClockHours({
8
9
  is24Hour,
@@ -11,9 +12,11 @@ function AnalogClockHours({
11
12
  is24Hour: boolean
12
13
  hours: number
13
14
  }) {
14
- const outerRange = getHourNumbers(false, circleSize, 12)
15
- const innerRange = getHourNumbers(true, circleSize, 12)
15
+ const { mode } = React.useContext(DisplayModeContext)
16
+ const outerRange = getHourNumbers(false, circleSize, 12, 12)
17
+ const innerRange = getHourNumbers(true, circleSize, 12, 12)
16
18
  const color = useTextColorOnPrimary()
19
+
17
20
  return (
18
21
  <>
19
22
  {outerRange.map((a, i) => (
@@ -29,8 +32,9 @@ function AnalogClockHours({
29
32
  ]}
30
33
  >
31
34
  <View style={styles.outerHourInner}>
35
+ {/* Display 00 instead of 12 for AM hours */}
32
36
  <Text style={hours === i + 1 ? { color } : null} selectable={false}>
33
- {i + 1}
37
+ {mode === 'AM' && i + 1 === 12 ? '00' : i + 1}
34
38
  </Text>
35
39
  </View>
36
40
  </View>
@@ -97,14 +101,19 @@ const styles = StyleSheet.create({
97
101
  innerHourText: { fontSize: 13 },
98
102
  })
99
103
 
100
- function getHourNumbers(is24Hour: boolean, size: number, count: number) {
104
+ function getHourNumbers(
105
+ is24Hour: boolean,
106
+ size: number,
107
+ count: number,
108
+ arrayLength: number
109
+ ) {
101
110
  let angle = 0
102
111
  let step = (2 * Math.PI) / count
103
112
  let radius = size / (is24Hour ? 4 : 2.5)
104
113
 
105
114
  angle = (-90 * Math.PI) / 180 + Math.PI / 6
106
115
 
107
- return Array(12)
116
+ return Array(arrayLength)
108
117
  .fill(true)
109
118
  .map(() => {
110
119
  let x = Math.round(size / 2 + radius * Math.cos(angle))
@@ -30,7 +30,10 @@ function AnalogClockMinutes({ minutes }: { minutes: number }) {
30
30
  ]}
31
31
  >
32
32
  <View style={styles.outerHourInner}>
33
- <Text style={isCurrent ? { color } : null} selectable={false}>
33
+ <Text
34
+ style={isCurrent ? { color } : undefined}
35
+ selectable={false}
36
+ >
34
37
  {isZero ? '00' : currentMinutes}
35
38
  </Text>
36
39
  </View>
@@ -96,6 +96,9 @@ function TimeInput(
96
96
  rippleColor={Color(theme.colors.primary).fade(0.7).hex()}
97
97
  onPress={() => onPress(clockType)}
98
98
  borderless={true}
99
+ // RN types bug
100
+ hasTVPreferredFocus={undefined}
101
+ tvParallaxProperties={undefined}
99
102
  >
100
103
  <View />
101
104
  </TouchableRipple>
@@ -35,11 +35,7 @@ function TimeInputs({
35
35
  hours: number
36
36
  minutes: number
37
37
  onFocusInput: (type: PossibleClockTypes) => any
38
- onChange: ({
39
- hours,
40
- minutes,
41
- focused,
42
- }: {
38
+ onChange: (hoursMinutesAndFocused: {
43
39
  hours: number
44
40
  minutes: number
45
41
  focused?: undefined | PossibleClockTypes