react-native-paper-dates 0.23.16 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/lib/commonjs/Date/AnimatedCrossView.js +2 -2
  2. package/lib/commonjs/Date/AnimatedCrossView.js.map +1 -1
  3. package/lib/commonjs/Date/AutoSizer.js +24 -11
  4. package/lib/commonjs/Date/AutoSizer.js.map +1 -1
  5. package/lib/commonjs/Date/Calendar.js +26 -5
  6. package/lib/commonjs/Date/Calendar.js.map +1 -1
  7. package/lib/commonjs/Date/CalendarEdit.js +70 -61
  8. package/lib/commonjs/Date/CalendarEdit.js.map +1 -1
  9. package/lib/commonjs/Date/CalendarHeader.js +30 -15
  10. package/lib/commonjs/Date/CalendarHeader.js.map +1 -1
  11. package/lib/commonjs/Date/DatePickerModal.js +5 -11
  12. package/lib/commonjs/Date/DatePickerModal.js.map +1 -1
  13. package/lib/commonjs/Date/DatePickerModalContent.js +52 -32
  14. package/lib/commonjs/Date/DatePickerModalContent.js.map +1 -1
  15. package/lib/commonjs/Date/DatePickerModalContentHeader.js +12 -5
  16. package/lib/commonjs/Date/DatePickerModalContentHeader.js.map +1 -1
  17. package/lib/commonjs/Date/DatePickerModalHeader.js +40 -40
  18. package/lib/commonjs/Date/DatePickerModalHeader.js.map +1 -1
  19. package/lib/commonjs/Date/DatePickerModalHeaderBackground.js +22 -4
  20. package/lib/commonjs/Date/DatePickerModalHeaderBackground.js.map +1 -1
  21. package/lib/commonjs/Date/Day.js +59 -2
  22. package/lib/commonjs/Date/Day.js.map +1 -1
  23. package/lib/commonjs/Date/Month.js +48 -28
  24. package/lib/commonjs/Date/Month.js.map +1 -1
  25. package/lib/commonjs/Date/Swiper.js +31 -21
  26. package/lib/commonjs/Date/Swiper.js.map +1 -1
  27. package/lib/commonjs/Date/Swiper.native.js +37 -21
  28. package/lib/commonjs/Date/Swiper.native.js.map +1 -1
  29. package/lib/commonjs/Date/SwiperUtils.js.map +1 -1
  30. package/lib/commonjs/Date/YearPicker.js +3 -1
  31. package/lib/commonjs/Date/YearPicker.js.map +1 -1
  32. package/lib/commonjs/Date/weekdayColumns.js +60 -0
  33. package/lib/commonjs/Date/weekdayColumns.js.map +1 -0
  34. package/lib/commonjs/shared/styles.js +3 -0
  35. package/lib/commonjs/shared/styles.js.map +1 -1
  36. package/lib/commonjs/shared/utils.js +9 -0
  37. package/lib/commonjs/shared/utils.js.map +1 -1
  38. package/lib/module/Date/AnimatedCrossView.js +2 -2
  39. package/lib/module/Date/AnimatedCrossView.js.map +1 -1
  40. package/lib/module/Date/AutoSizer.js +25 -12
  41. package/lib/module/Date/AutoSizer.js.map +1 -1
  42. package/lib/module/Date/Calendar.js +26 -5
  43. package/lib/module/Date/Calendar.js.map +1 -1
  44. package/lib/module/Date/CalendarEdit.js +70 -61
  45. package/lib/module/Date/CalendarEdit.js.map +1 -1
  46. package/lib/module/Date/CalendarHeader.js +31 -16
  47. package/lib/module/Date/CalendarHeader.js.map +1 -1
  48. package/lib/module/Date/DatePickerModal.js +7 -13
  49. package/lib/module/Date/DatePickerModal.js.map +1 -1
  50. package/lib/module/Date/DatePickerModalContent.js +52 -32
  51. package/lib/module/Date/DatePickerModalContent.js.map +1 -1
  52. package/lib/module/Date/DatePickerModalContentHeader.js +12 -5
  53. package/lib/module/Date/DatePickerModalContentHeader.js.map +1 -1
  54. package/lib/module/Date/DatePickerModalHeader.js +43 -43
  55. package/lib/module/Date/DatePickerModalHeader.js.map +1 -1
  56. package/lib/module/Date/DatePickerModalHeaderBackground.js +24 -6
  57. package/lib/module/Date/DatePickerModalHeaderBackground.js.map +1 -1
  58. package/lib/module/Date/Day.js +59 -2
  59. package/lib/module/Date/Day.js.map +1 -1
  60. package/lib/module/Date/Month.js +50 -30
  61. package/lib/module/Date/Month.js.map +1 -1
  62. package/lib/module/Date/Swiper.js +32 -22
  63. package/lib/module/Date/Swiper.js.map +1 -1
  64. package/lib/module/Date/Swiper.native.js +38 -22
  65. package/lib/module/Date/Swiper.native.js.map +1 -1
  66. package/lib/module/Date/SwiperUtils.js.map +1 -1
  67. package/lib/module/Date/YearPicker.js +4 -2
  68. package/lib/module/Date/YearPicker.js.map +1 -1
  69. package/lib/module/Date/weekdayColumns.js +51 -0
  70. package/lib/module/Date/weekdayColumns.js.map +1 -0
  71. package/lib/module/shared/styles.js +3 -0
  72. package/lib/module/shared/styles.js.map +1 -1
  73. package/lib/module/shared/utils.js +8 -0
  74. package/lib/module/shared/utils.js.map +1 -1
  75. package/lib/typescript/Date/AnimatedCrossView.d.ts.map +1 -1
  76. package/lib/typescript/Date/AutoSizer.d.ts.map +1 -1
  77. package/lib/typescript/Date/Calendar.d.ts +28 -0
  78. package/lib/typescript/Date/Calendar.d.ts.map +1 -1
  79. package/lib/typescript/Date/CalendarEdit.d.ts +3 -1
  80. package/lib/typescript/Date/CalendarEdit.d.ts.map +1 -1
  81. package/lib/typescript/Date/CalendarHeader.d.ts +5 -1
  82. package/lib/typescript/Date/CalendarHeader.d.ts.map +1 -1
  83. package/lib/typescript/Date/DatePickerModal.d.ts.map +1 -1
  84. package/lib/typescript/Date/DatePickerModalContent.d.ts.map +1 -1
  85. package/lib/typescript/Date/DatePickerModalContentHeader.d.ts +2 -0
  86. package/lib/typescript/Date/DatePickerModalContentHeader.d.ts.map +1 -1
  87. package/lib/typescript/Date/DatePickerModalHeader.d.ts +2 -0
  88. package/lib/typescript/Date/DatePickerModalHeader.d.ts.map +1 -1
  89. package/lib/typescript/Date/DatePickerModalHeaderBackground.d.ts +3 -1
  90. package/lib/typescript/Date/DatePickerModalHeaderBackground.d.ts.map +1 -1
  91. package/lib/typescript/Date/Day.d.ts +5 -0
  92. package/lib/typescript/Date/Day.d.ts.map +1 -1
  93. package/lib/typescript/Date/Month.d.ts +5 -1
  94. package/lib/typescript/Date/Month.d.ts.map +1 -1
  95. package/lib/typescript/Date/Swiper.d.ts.map +1 -1
  96. package/lib/typescript/Date/Swiper.native.d.ts.map +1 -1
  97. package/lib/typescript/Date/SwiperUtils.d.ts +1 -0
  98. package/lib/typescript/Date/SwiperUtils.d.ts.map +1 -1
  99. package/lib/typescript/Date/YearPicker.d.ts.map +1 -1
  100. package/lib/typescript/Date/weekdayColumns.d.ts +9 -0
  101. package/lib/typescript/Date/weekdayColumns.d.ts.map +1 -0
  102. package/lib/typescript/shared/styles.d.ts +3 -0
  103. package/lib/typescript/shared/styles.d.ts.map +1 -1
  104. package/lib/typescript/shared/utils.d.ts +1 -0
  105. package/lib/typescript/shared/utils.d.ts.map +1 -1
  106. package/package.json +1 -1
  107. package/src/Date/AnimatedCrossView.tsx +2 -1
  108. package/src/Date/AutoSizer.tsx +33 -9
  109. package/src/Date/Calendar.tsx +48 -4
  110. package/src/Date/CalendarEdit.tsx +60 -51
  111. package/src/Date/CalendarHeader.tsx +38 -6
  112. package/src/Date/DatePickerModal.tsx +5 -13
  113. package/src/Date/DatePickerModalContent.tsx +58 -37
  114. package/src/Date/DatePickerModalContentHeader.tsx +14 -3
  115. package/src/Date/DatePickerModalHeader.tsx +47 -50
  116. package/src/Date/DatePickerModalHeaderBackground.tsx +30 -8
  117. package/src/Date/Day.tsx +51 -0
  118. package/src/Date/Month.tsx +82 -41
  119. package/src/Date/Swiper.native.tsx +70 -43
  120. package/src/Date/Swiper.tsx +44 -19
  121. package/src/Date/SwiperUtils.ts +1 -0
  122. package/src/Date/YearPicker.tsx +14 -2
  123. package/src/Date/weekdayColumns.ts +75 -0
  124. package/src/shared/styles.tsx +3 -0
  125. package/src/shared/utils.ts +6 -0
package/src/Date/Day.tsx CHANGED
@@ -1,9 +1,11 @@
1
1
  import { Text, TouchableRipple } from 'react-native-paper'
2
2
  import { StyleSheet, View } from 'react-native'
3
+ import type { StyleProp, ViewStyle } from 'react-native'
3
4
  import DayRange from './DayRange'
4
5
  import { daySize } from './dateUtils'
5
6
 
6
7
  import type { PaperTheme } from '../shared/utils'
8
+ import type { DayContentPosition, DayContentRenderer } from './Calendar'
7
9
  import { memo, useCallback } from 'react'
8
10
 
9
11
  function EmptyDayPure() {
@@ -27,6 +29,9 @@ function Day(props: {
27
29
  isToday: boolean
28
30
  disabled: boolean
29
31
  onPressDate: (date: Date) => any
32
+ dayContent?: DayContentRenderer
33
+ dayContentPosition?: DayContentPosition
34
+ dayContentStyle?: StyleProp<ViewStyle>
30
35
  }) {
31
36
  const {
32
37
  day,
@@ -42,6 +47,9 @@ function Day(props: {
42
47
  isToday,
43
48
  disabled,
44
49
  theme,
50
+ dayContent,
51
+ dayContentPosition,
52
+ dayContentStyle,
45
53
  } = props
46
54
  const borderColor = theme.colors.primary
47
55
 
@@ -111,6 +119,26 @@ function Day(props: {
111
119
  </Text>
112
120
  </View>
113
121
  </TouchableRipple>
122
+ {dayContent ? (
123
+ <View
124
+ style={[
125
+ styles.content,
126
+ contentPositions[dayContentPosition || 'bottom'],
127
+ dayContentStyle,
128
+ ]}
129
+ pointerEvents="none"
130
+ >
131
+ {dayContent({
132
+ date: new Date(year, month, day),
133
+ day,
134
+ month,
135
+ year,
136
+ selected,
137
+ isToday,
138
+ disabled,
139
+ })}
140
+ </View>
141
+ ) : null}
114
142
  </View>
115
143
  )
116
144
  }
@@ -122,6 +150,14 @@ const styles = StyleSheet.create({
122
150
  overflow: 'hidden',
123
151
  borderRadius: daySize / 2,
124
152
  },
153
+ content: {
154
+ // Absolutely positioned without insets, so Yoga still honours the parent's
155
+ // centering and this box lines up with the day circle instead of the
156
+ // (wider) grid cell.
157
+ position: 'absolute',
158
+ width: daySize,
159
+ height: daySize,
160
+ },
125
161
  day: {
126
162
  flexBasis: 0,
127
163
  flex: 1,
@@ -149,4 +185,19 @@ const styles = StyleSheet.create({
149
185
  },
150
186
  })
151
187
 
188
+ // Anchors for `dayContent`, applied to a box the size of the day circle.
189
+ const contentPositions = StyleSheet.create({
190
+ 'bottom': {
191
+ justifyContent: 'flex-end',
192
+ alignItems: 'center',
193
+ paddingBottom: 2,
194
+ },
195
+ 'bottom-left': { justifyContent: 'flex-end', alignItems: 'flex-start' },
196
+ 'bottom-right': { justifyContent: 'flex-end', alignItems: 'flex-end' },
197
+ 'center': { justifyContent: 'center', alignItems: 'center' },
198
+ 'top': { justifyContent: 'flex-start', alignItems: 'center', paddingTop: 2 },
199
+ 'top-left': { justifyContent: 'flex-start', alignItems: 'flex-start' },
200
+ 'top-right': { justifyContent: 'flex-start', alignItems: 'flex-end' },
201
+ })
202
+
152
203
  export default memo(Day)
@@ -1,4 +1,4 @@
1
- import { StyleSheet, View } from 'react-native'
1
+ import { Platform, ScrollView, StyleSheet, View } from 'react-native'
2
2
  import { Icon, Text, TouchableRipple, useTheme } from 'react-native-paper'
3
3
  import Day, { EmptyDay } from './Day'
4
4
 
@@ -19,10 +19,14 @@ import {
19
19
  showWeekDay,
20
20
  useRangeChecker,
21
21
  } from './dateUtils'
22
+ import { alignTextToFirstWeekday } from './weekdayColumns'
22
23
  import { getCalendarHeaderHeight } from './CalendarHeader'
24
+ import type { StyleProp, ViewStyle } from 'react-native'
23
25
  import type {
24
26
  CalendarDate,
25
27
  CalendarDates,
28
+ DayContentPosition,
29
+ DayContentRenderer,
26
30
  ModeType,
27
31
  ValidRangeType,
28
32
  } from './Calendar'
@@ -52,6 +56,9 @@ interface BaseMonthProps {
52
56
  endDate?: CalendarDate
53
57
  date?: CalendarDate
54
58
  dates?: CalendarDates
59
+ dayContent?: DayContentRenderer
60
+ dayContentPosition?: DayContentPosition
61
+ dayContentStyle?: StyleProp<ViewStyle>
55
62
  }
56
63
 
57
64
  interface MonthRangeProps extends BaseMonthProps {
@@ -91,6 +98,9 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
91
98
  startWeekOnMonday,
92
99
  startYear,
93
100
  endYear,
101
+ dayContent,
102
+ dayContentPosition,
103
+ dayContentStyle,
94
104
  } = props
95
105
  const isHorizontal = scrollMode === 'horizontal'
96
106
 
@@ -263,17 +273,54 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
263
273
 
264
274
  const iconSource = selectingYear ? 'menu-up' : 'menu-down'
265
275
 
276
+ const weeks = grid.map(({ weekIndex, generatedDays }) => (
277
+ <View style={styles.week} key={weekIndex}>
278
+ {generatedDays
279
+ .filter((gd) => showWeekDay(gd.dayIndex, disableWeekDays))
280
+ .map((gd) =>
281
+ gd.beforeWeekDay || gd.afterWeekDay ? (
282
+ <EmptyDay key={gd.dayIndex} />
283
+ ) : (
284
+ <Day
285
+ key={gd.dayIndex}
286
+ theme={theme}
287
+ day={gd.dayOfMonth}
288
+ month={gd.month}
289
+ year={gd.year}
290
+ selected={gd.selected}
291
+ inRange={gd.inRange}
292
+ leftCrop={gd.leftCrop}
293
+ rightCrop={gd.rightCrop}
294
+ onPressDate={onPressDate}
295
+ isToday={gd.isToday}
296
+ selectColor={selectColor}
297
+ primaryColor={primaryColor}
298
+ disabled={gd.disabled}
299
+ textColorOnPrimary={textColorOnPrimary}
300
+ dayContent={dayContent}
301
+ dayContentPosition={dayContentPosition}
302
+ dayContentStyle={dayContentStyle}
303
+ />
304
+ )
305
+ )}
306
+ </View>
307
+ ))
308
+
266
309
  return (
267
310
  <View
268
- style={{
269
- height: getMonthHeight(
270
- scrollMode,
271
- index,
272
- startWeekOnMonday,
273
- startYear,
274
- endYear
275
- ),
276
- }}
311
+ style={
312
+ isHorizontal
313
+ ? styles.monthFill
314
+ : {
315
+ height: getMonthHeight(
316
+ scrollMode,
317
+ index,
318
+ startWeekOnMonday,
319
+ startYear,
320
+ endYear
321
+ ),
322
+ }
323
+ }
277
324
  >
278
325
  <View
279
326
  style={[
@@ -296,6 +343,7 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
296
343
  {
297
344
  borderRadius: roundness,
298
345
  },
346
+ alignTextToFirstWeekday(disableWeekDays),
299
347
  ]}
300
348
  >
301
349
  <View
@@ -330,35 +378,26 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
330
378
  </View>
331
379
  </TouchableRipple>
332
380
  </View>
333
- {grid.map(({ weekIndex, generatedDays }) => (
334
- <View style={styles.week} key={weekIndex}>
335
- {generatedDays
336
- .filter((gd) => showWeekDay(gd.dayIndex, disableWeekDays))
337
- .map((gd) =>
338
- gd.beforeWeekDay || gd.afterWeekDay ? (
339
- <EmptyDay key={gd.dayIndex} />
340
- ) : (
341
- <Day
342
- key={gd.dayIndex}
343
- theme={theme}
344
- day={gd.dayOfMonth}
345
- month={gd.month}
346
- year={gd.year}
347
- selected={gd.selected}
348
- inRange={gd.inRange}
349
- leftCrop={gd.leftCrop}
350
- rightCrop={gd.rightCrop}
351
- onPressDate={onPressDate}
352
- isToday={gd.isToday}
353
- selectColor={selectColor}
354
- primaryColor={primaryColor}
355
- disabled={gd.disabled}
356
- textColorOnPrimary={textColorOnPrimary}
357
- />
358
- )
359
- )}
360
- </View>
361
- ))}
381
+ {isHorizontal ? (
382
+ <ScrollView
383
+ alwaysBounceVertical={false}
384
+ directionalLockEnabled
385
+ keyboardShouldPersistTaps="handled"
386
+ nestedScrollEnabled
387
+ style={[
388
+ sharedStyles.root,
389
+ sharedStyles.minHeightZero,
390
+ Platform.OS === 'web'
391
+ ? ({ colorScheme: theme.dark ? 'dark' : 'light' } as ViewStyle)
392
+ : null,
393
+ ]}
394
+ testID="react-native-paper-dates-month-days-scroll"
395
+ >
396
+ {weeks}
397
+ </ScrollView>
398
+ ) : (
399
+ weeks
400
+ )}
362
401
  </View>
363
402
  )
364
403
  }
@@ -375,6 +414,10 @@ const styles = StyleSheet.create({
375
414
  iconWrapper: {
376
415
  padding: 8,
377
416
  },
417
+ monthFill: {
418
+ flex: 1,
419
+ minHeight: 0,
420
+ },
378
421
  monthHeader: {
379
422
  height: montHeaderHeight,
380
423
  justifyContent: 'center',
@@ -391,10 +434,8 @@ const styles = StyleSheet.create({
391
434
  },
392
435
  yearButton: {
393
436
  alignSelf: 'flex-start',
394
- marginLeft: 6,
395
437
  },
396
438
  yearButtonInner: {
397
- paddingLeft: 16,
398
439
  flexDirection: 'row',
399
440
  alignItems: 'center',
400
441
  },
@@ -20,8 +20,9 @@ import {
20
20
  getBeginOffset,
21
21
  } from './dateUtils'
22
22
  import AutoSizer from './AutoSizer'
23
- import { memo, useCallback, useRef, useState } from 'react'
23
+ import { memo, useCallback, useEffect, useRef, useState } from 'react'
24
24
  import { sharedStyles } from '../shared/styles'
25
+ import { verticalScrollbarGutter } from './CalendarHeader'
25
26
 
26
27
  function getVisibleArray(
27
28
  i: number,
@@ -124,10 +125,13 @@ function SwiperInner({
124
125
  }
125
126
  }, [scrollTo, idx, startYear, endYear])
126
127
 
127
- const scrollToInitial = useCallback(() => {
128
+ const scrollToCurrent = useCallback(() => {
128
129
  scrollTo(idx.current, false)
129
130
  }, [scrollTo])
130
131
 
132
+ // onLayout can run against the previous page width during rotation, before
133
+ useEffect(scrollToCurrent, [scrollToCurrent])
134
+
131
135
  const onMomentumScrollEnd = useCallback(
132
136
  (e: NativeSyntheticEvent<NativeScrollEvent>) => {
133
137
  const contentOffset = e.nativeEvent.contentOffset
@@ -164,6 +168,19 @@ function SwiperInner({
164
168
  onNext,
165
169
  }
166
170
 
171
+ const needsMonthScroll =
172
+ isHorizontal &&
173
+ visibleIndexes.some(
174
+ (monthIndex) =>
175
+ getMonthHeight(
176
+ scrollMode,
177
+ monthIndex,
178
+ startWeekOnMonday,
179
+ startYear,
180
+ endYear
181
+ ) > height
182
+ )
183
+
167
184
  useYearChange(
168
185
  (newIndex) => {
169
186
  if (newIndex && isIndexWithinRange(newIndex, startYear, endYear)) {
@@ -185,10 +202,12 @@ function SwiperInner({
185
202
  ref={parentRef}
186
203
  horizontal={isHorizontal}
187
204
  pagingEnabled={isHorizontal}
188
- style={sharedStyles.root}
205
+ nestedScrollEnabled={isHorizontal}
206
+ directionalLockEnabled={isHorizontal}
207
+ style={[sharedStyles.root, sharedStyles.minHeightZero]}
189
208
  onMomentumScrollEnd={onMomentumScrollEnd}
190
209
  onScrollEndDrag={onMomentumScrollEnd}
191
- onLayout={scrollToInitial}
210
+ onLayout={scrollToCurrent}
192
211
  showsHorizontalScrollIndicator={false}
193
212
  showsVerticalScrollIndicator={false}
194
213
  decelerationRate="fast"
@@ -208,48 +227,56 @@ function SwiperInner({
208
227
  ]}
209
228
  >
210
229
  {visibleIndexes
211
- ? new Array(visibleIndexes.length).fill(undefined).map((_, vi) => (
212
- <View
213
- key={vi}
214
- // eslint-disable-next-line react-native/no-inline-styles
215
- style={{
216
- top: isHorizontal
217
- ? 0
218
- : getVerticalMonthsOffset(
219
- visibleIndexes[vi],
220
- startWeekOnMonday,
221
- startYear,
222
- endYear
223
- ),
224
- left: isHorizontal
225
- ? getHorizontalMonthOffset(visibleIndexes[vi], width)
226
- : 0,
227
- right: isHorizontal ? undefined : 0,
228
- bottom: isHorizontal ? 0 : undefined,
229
- position: 'absolute',
230
- width: isHorizontal ? width : undefined,
231
- height: isHorizontal
232
- ? undefined
233
- : getMonthHeight(
234
- scrollMode,
235
- visibleIndexes[vi],
236
- startWeekOnMonday,
237
- startYear,
238
- endYear
239
- ),
240
- }}
241
- >
242
- {renderItem({
243
- index: visibleIndexes[vi],
244
- onPrev: onPrev,
245
- onNext: onNext,
246
- })}
247
- </View>
248
- ))
230
+ ? new Array(visibleIndexes.length).fill(undefined).map((_, vi) => {
231
+ const monthIndex = visibleIndexes[vi]
232
+ const monthHeight = getMonthHeight(
233
+ scrollMode,
234
+ monthIndex,
235
+ startWeekOnMonday,
236
+ startYear,
237
+ endYear
238
+ )
239
+ // Horizontal paging does not scroll inside a month. Bound the
240
+ // page to the dialog so the day grid can scroll in landscape.
241
+ return (
242
+ <View
243
+ key={vi}
244
+ // eslint-disable-next-line react-native/no-inline-styles
245
+ style={{
246
+ top: isHorizontal
247
+ ? 0
248
+ : getVerticalMonthsOffset(
249
+ monthIndex,
250
+ startWeekOnMonday,
251
+ startYear,
252
+ endYear
253
+ ),
254
+ left: isHorizontal
255
+ ? getHorizontalMonthOffset(monthIndex, width)
256
+ : 0,
257
+ right: isHorizontal ? undefined : 0,
258
+ position: 'absolute',
259
+ width: isHorizontal ? width : undefined,
260
+ height: isHorizontal ? height : monthHeight,
261
+ overflow: 'hidden',
262
+ }}
263
+ >
264
+ {renderItem({
265
+ index: monthIndex,
266
+ onPrev: onPrev,
267
+ onNext: onNext,
268
+ })}
269
+ </View>
270
+ )
271
+ })
249
272
  : null}
250
273
  </View>
251
274
  </ScrollView>
252
- {renderHeader && renderHeader(renderProps)}
275
+ {renderHeader &&
276
+ renderHeader({
277
+ ...renderProps,
278
+ endInset: needsMonthScroll ? verticalScrollbarGutter : 0,
279
+ })}
253
280
  {renderFooter && renderFooter(renderProps)}
254
281
  </>
255
282
  )
@@ -1,4 +1,3 @@
1
- import { View } from 'react-native'
2
1
  import { useTheme } from 'react-native-paper'
3
2
  import {
4
3
  getIndexFromVerticalOffset,
@@ -30,7 +29,7 @@ import {
30
29
  useRef,
31
30
  useState,
32
31
  } from 'react'
33
- import { sharedStyles } from '../shared/styles'
32
+ import { verticalScrollbarGutter } from './CalendarHeader'
34
33
 
35
34
  const useIsomorphicLayoutEffect =
36
35
  typeof window !== 'undefined' ? useLayoutEffect : useEffect
@@ -94,26 +93,52 @@ function Swiper({
94
93
 
95
94
  return (
96
95
  <>
97
- {renderHeader && renderHeader(renderProps)}
98
96
  {isHorizontal ? (
99
- <View style={sharedStyles.root}>
100
- {renderItem({ index, onPrev, onNext })}
101
- </View>
102
- ) : (
103
97
  <AutoSizer>
104
- {({ width, height }) => (
105
- <VerticalScroller
106
- width={width}
107
- height={height}
108
- initialIndex={initialIndex}
109
- estimatedHeight={estimatedMonthHeight}
110
- renderItem={renderItem}
111
- startWeekOnMonday={startWeekOnMonday}
112
- startYear={startYear}
113
- endYear={endYear}
114
- />
115
- )}
98
+ {({ height }) => {
99
+ const overflow =
100
+ getMonthHeight(
101
+ 'horizontal',
102
+ index,
103
+ startWeekOnMonday,
104
+ startYear,
105
+ endYear
106
+ ) > height
107
+ return (
108
+ <>
109
+ {renderItem({
110
+ index,
111
+ onPrev,
112
+ onNext,
113
+ })}
114
+ {renderHeader
115
+ ? renderHeader({
116
+ ...renderProps,
117
+ endInset: overflow ? verticalScrollbarGutter : 0,
118
+ })
119
+ : null}
120
+ </>
121
+ )
122
+ }}
116
123
  </AutoSizer>
124
+ ) : (
125
+ <>
126
+ {renderHeader && renderHeader(renderProps)}
127
+ <AutoSizer>
128
+ {({ width, height }) => (
129
+ <VerticalScroller
130
+ width={width}
131
+ height={height}
132
+ initialIndex={initialIndex}
133
+ estimatedHeight={estimatedMonthHeight}
134
+ renderItem={renderItem}
135
+ startWeekOnMonday={startWeekOnMonday}
136
+ startYear={startYear}
137
+ endYear={endYear}
138
+ />
139
+ )}
140
+ </AutoSizer>
141
+ </>
117
142
  )}
118
143
  {renderFooter && renderFooter(renderProps)}
119
144
  </>
@@ -10,6 +10,7 @@ import {
10
10
  import { defaultStartYear, defaultEndYear } from './dateUtils'
11
11
 
12
12
  export type RenderProps = {
13
+ endInset?: number
13
14
  index: number
14
15
  onNext: () => any
15
16
  onPrev: () => any
@@ -1,4 +1,11 @@
1
- import { FlatList, ScrollView, StyleSheet, View } from 'react-native'
1
+ import {
2
+ FlatList,
3
+ Platform,
4
+ ScrollView,
5
+ StyleSheet,
6
+ View,
7
+ type ViewStyle,
8
+ } from 'react-native'
2
9
  import { Text, TouchableRipple, useTheme } from 'react-native-paper'
3
10
  import { range } from '../shared/utils'
4
11
  import { memo, useEffect, useRef } from 'react'
@@ -51,7 +58,12 @@ export default function YearPicker({
51
58
  >
52
59
  <FlatList<number>
53
60
  ref={flatList}
54
- style={sharedStyles.root}
61
+ style={[
62
+ sharedStyles.root,
63
+ Platform.OS === 'web'
64
+ ? ({ colorScheme: theme.dark ? 'dark' : 'light' } as ViewStyle)
65
+ : null,
66
+ ]}
55
67
  data={years}
56
68
  renderScrollComponent={(sProps) => {
57
69
  return <ScrollView {...sProps} />
@@ -0,0 +1,75 @@
1
+ import { I18nManager, type DimensionValue, type ViewStyle } from 'react-native'
2
+ import { showWeekDay, type DisableWeekDaysType } from './dateUtils'
3
+
4
+ const compactTextButtonPadding = 8
5
+ const iconButtonPadding = 8
6
+ const iconButtonSize = 24 + 2 * iconButtonPadding
7
+ const letterHalfWidth = 4
8
+
9
+ export function alignIconToFirstWeekday(
10
+ disableWeekDays?: DisableWeekDaysType
11
+ ): ViewStyle {
12
+ return alignToFirstColumn(
13
+ disableWeekDays,
14
+ letterHalfWidth + iconButtonPadding
15
+ )
16
+ }
17
+
18
+ export function alignTextToFirstWeekday(
19
+ disableWeekDays?: DisableWeekDaysType
20
+ ): ViewStyle {
21
+ return alignToFirstColumn(disableWeekDays, letterHalfWidth)
22
+ }
23
+
24
+ export function alignTextToLastWeekday(
25
+ disableWeekDays?: DisableWeekDaysType
26
+ ): ViewStyle {
27
+ return alignToLastColumn(
28
+ disableWeekDays,
29
+ letterHalfWidth + compactTextButtonPadding
30
+ )
31
+ }
32
+
33
+ function alignToFirstColumn(
34
+ disableWeekDays: DisableWeekDaysType | undefined,
35
+ nudge: number
36
+ ): ViewStyle {
37
+ return {
38
+ marginStart: columnCentreInset(disableWeekDays),
39
+ transform: [{ translateX: I18nManager.isRTL ? nudge : -nudge }],
40
+ }
41
+ }
42
+
43
+ function alignToLastColumn(
44
+ disableWeekDays: DisableWeekDaysType | undefined,
45
+ nudge: number
46
+ ): ViewStyle {
47
+ return {
48
+ marginEnd: columnCentreInset(disableWeekDays),
49
+ transform: [{ translateX: I18nManager.isRTL ? -nudge : nudge }],
50
+ }
51
+ }
52
+
53
+ export function centerIconOnLastWeekday(
54
+ disableWeekDays?: DisableWeekDaysType
55
+ ): ViewStyle {
56
+ return alignToLastColumn(disableWeekDays, iconButtonSize / 2)
57
+ }
58
+
59
+ function columnCentreInset(
60
+ disableWeekDays: DisableWeekDaysType | undefined
61
+ ): DimensionValue {
62
+ const visibleColumns = [0, 1, 2, 3, 4, 5, 6].filter((dayIndex) =>
63
+ showWeekDay(dayIndex, disableWeekDays)
64
+ ).length
65
+ return `${50 / (visibleColumns || 7)}%`
66
+ }
67
+
68
+ export function weekdaySpan(disableWeekDays?: DisableWeekDaysType): ViewStyle {
69
+ const inset = columnCentreInset(disableWeekDays)
70
+ return { marginStart: inset, marginEnd: inset }
71
+ }
72
+
73
+ export const weekdaySpanOvershoot: ViewStyle = {
74
+ marginHorizontal: -letterHalfWidth,
75
+ }
@@ -4,6 +4,9 @@ export const sharedStyles = StyleSheet.create({
4
4
  flexDirectionRow: {
5
5
  flexDirection: 'row',
6
6
  },
7
+ minHeightZero: {
8
+ minHeight: 0,
9
+ },
7
10
  opacity0: {
8
11
  opacity: 0,
9
12
  },
@@ -1,4 +1,5 @@
1
1
  import { useRef } from 'react'
2
+ import { useWindowDimensions } from 'react-native'
2
3
  import { DefaultTheme, MD3DarkTheme, useTheme } from 'react-native-paper'
3
4
  import Color from 'color'
4
5
 
@@ -24,6 +25,11 @@ export function useLatest<T>(value: T) {
24
25
  return ref
25
26
  }
26
27
 
28
+ export function useIsLargeScreen() {
29
+ const { width, height } = useWindowDimensions()
30
+ return width > 650 && height > 650
31
+ }
32
+
27
33
  export function useHeaderBackgroundColor() {
28
34
  const theme = useTheme()
29
35
  return theme.colors.elevation.level3