react-native-molecules 0.5.0-beta.16 → 0.5.0-beta.17

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 (81) hide show
  1. package/components/DateField/DateField.tsx +110 -0
  2. package/components/DateField/index.tsx +6 -0
  3. package/components/{DatePickerInput/inputUtils.ts → DateField/useDateFieldState.ts} +17 -49
  4. package/components/DatePicker/DateCalendar.tsx +83 -0
  5. package/components/DatePicker/DatePickerActions.tsx +73 -0
  6. package/components/DatePicker/DatePickerModal.tsx +234 -0
  7. package/components/DatePicker/DatePickerPopover.tsx +79 -0
  8. package/components/DatePicker/DatePickerProvider.tsx +152 -0
  9. package/components/DatePicker/DatePickerTrigger.tsx +23 -0
  10. package/components/DatePicker/context.tsx +82 -0
  11. package/components/DatePicker/index.tsx +44 -0
  12. package/components/DatePicker/utils.ts +292 -0
  13. package/components/DatePickerInline/DatePickerContext.tsx +1 -0
  14. package/components/DatePickerInline/DatePickerDockedHeader.tsx +113 -0
  15. package/components/DatePickerInline/DatePickerInline.tsx +16 -15
  16. package/components/DatePickerInline/DatePickerInlineBase.tsx +7 -1
  17. package/components/DatePickerInline/Day.tsx +25 -1
  18. package/components/DatePickerInline/DayRange.tsx +2 -4
  19. package/components/DatePickerInline/HeaderItem.tsx +42 -27
  20. package/components/DatePickerInline/Month.tsx +45 -65
  21. package/components/DatePickerInline/MonthPicker.tsx +25 -41
  22. package/components/DatePickerInline/Swiper.native.tsx +21 -4
  23. package/components/DatePickerInline/Swiper.tsx +168 -13
  24. package/components/DatePickerInline/Week.tsx +6 -1
  25. package/components/DatePickerInline/YearPicker.tsx +206 -53
  26. package/components/DatePickerInline/dateUtils.tsx +17 -12
  27. package/components/DatePickerInline/types.ts +3 -0
  28. package/components/DatePickerInline/utils.ts +66 -29
  29. package/components/ListItem/ListItem.tsx +3 -1
  30. package/components/ListItem/utils.ts +1 -1
  31. package/components/LoadingIndicator/index.tsx +1 -1
  32. package/components/Popover/Popover.native.tsx +4 -25
  33. package/components/Popover/Popover.tsx +4 -26
  34. package/components/Popover/utils.ts +41 -0
  35. package/components/Select/Select.tsx +7 -8
  36. package/components/Select/context.tsx +72 -0
  37. package/components/Select/index.ts +1 -0
  38. package/components/Select/utils.ts +0 -71
  39. package/components/Slot/compose-refs.tsx +2 -0
  40. package/components/TimeField/TimeField.tsx +75 -0
  41. package/components/TimeField/index.tsx +6 -0
  42. package/components/TimeField/useTimeFieldState.ts +70 -0
  43. package/components/{TimePickerField/sanitizeTime.ts → TimeField/utils.ts} +77 -10
  44. package/components/TimePicker/TimePicker.tsx +53 -9
  45. package/components/TimePicker/TimePickerModal.tsx +186 -0
  46. package/components/TimePicker/context.tsx +17 -0
  47. package/components/TimePicker/index.tsx +15 -3
  48. package/components/TimePicker/utils.ts +50 -0
  49. package/hooks/useActionState.tsx +19 -8
  50. package/package.json +6 -1
  51. package/components/DatePickerDocked/DatePickerDocked.tsx +0 -30
  52. package/components/DatePickerDocked/DatePickerDockedHeader.tsx +0 -129
  53. package/components/DatePickerDocked/index.tsx +0 -17
  54. package/components/DatePickerDocked/types.ts +0 -11
  55. package/components/DatePickerDocked/utils.ts +0 -157
  56. package/components/DatePickerInput/DatePickerInput.tsx +0 -130
  57. package/components/DatePickerInput/DatePickerInputModal.tsx +0 -48
  58. package/components/DatePickerInput/DatePickerInputWithoutModal.tsx +0 -73
  59. package/components/DatePickerInput/DateRangeInput.tsx +0 -88
  60. package/components/DatePickerInput/index.tsx +0 -11
  61. package/components/DatePickerInput/types.ts +0 -26
  62. package/components/DatePickerInput/utils.ts +0 -24
  63. package/components/DatePickerModal/AnimatedCrossView.tsx +0 -94
  64. package/components/DatePickerModal/CalendarEdit.tsx +0 -140
  65. package/components/DatePickerModal/DatePickerModal.tsx +0 -85
  66. package/components/DatePickerModal/DatePickerModalContent.tsx +0 -155
  67. package/components/DatePickerModal/DatePickerModalContentHeader.tsx +0 -213
  68. package/components/DatePickerModal/DatePickerModalHeader.tsx +0 -74
  69. package/components/DatePickerModal/DatePickerModalHeaderBackground.tsx +0 -13
  70. package/components/DatePickerModal/index.tsx +0 -16
  71. package/components/DatePickerModal/types.ts +0 -92
  72. package/components/DatePickerModal/utils.ts +0 -122
  73. package/components/DateTimePicker/DateTimePicker.tsx +0 -172
  74. package/components/DateTimePicker/index.tsx +0 -10
  75. package/components/DateTimePicker/utils.ts +0 -12
  76. package/components/TimePickerField/TimePickerField.tsx +0 -154
  77. package/components/TimePickerField/index.tsx +0 -10
  78. package/components/TimePickerField/utils.ts +0 -94
  79. package/components/TimePickerModal/TimePickerModal.tsx +0 -119
  80. package/components/TimePickerModal/index.tsx +0 -10
  81. package/components/TimePickerModal/utils.ts +0 -47
@@ -0,0 +1,113 @@
1
+ import { add, format, setYear } from 'date-fns';
2
+ import { memo, useCallback, useMemo } from 'react';
3
+ import { View, type ViewStyle } from 'react-native';
4
+ import { StyleSheet } from 'react-native-unistyles';
5
+
6
+ import { useDatePickerStoreRef, useDatePickerStoreValue } from './DatePickerContext';
7
+ import type { DisableWeekDaysType } from './dateUtils';
8
+ import DayNames from './DayNames';
9
+ import HeaderItem from './HeaderItem';
10
+ import { datePickerHeaderStyles } from './utils';
11
+
12
+ export type DockedHeaderProps = {
13
+ locale?: string;
14
+ scrollMode: 'horizontal' | 'vertical';
15
+ disableWeekDays?: DisableWeekDaysType;
16
+ style?: ViewStyle;
17
+ };
18
+
19
+ function DatePickerDockedHeader({
20
+ locale = 'en',
21
+ scrollMode,
22
+ disableWeekDays,
23
+ style: styleProp,
24
+ }: DockedHeaderProps) {
25
+ const setStore = useDatePickerStoreRef().set;
26
+ const { localDate, pickerType } = useDatePickerStoreValue(state => ({
27
+ localDate: state.localDate,
28
+ pickerType: state.pickerType,
29
+ }));
30
+ const isHorizontal = scrollMode === 'horizontal';
31
+
32
+ const { monthName, year } = useMemo(
33
+ () => ({ monthName: format(localDate, 'LLL'), year: localDate.getFullYear() }),
34
+ [localDate],
35
+ );
36
+
37
+ const handleMonthDropdown = useCallback(() => {
38
+ setStore(prev => ({ pickerType: prev.pickerType === 'month' ? undefined : 'month' }));
39
+ }, [setStore]);
40
+
41
+ const handleYearDropdown = useCallback(() => {
42
+ setStore(prev => ({ pickerType: prev.pickerType === 'year' ? undefined : 'year' }));
43
+ }, [setStore]);
44
+
45
+ const handleMonthPrev = useCallback(() => {
46
+ setStore(prev => ({ localDate: add(prev.localDate, { months: -1 }) }));
47
+ }, [setStore]);
48
+
49
+ const handleMonthNext = useCallback(() => {
50
+ setStore(prev => ({ localDate: add(prev.localDate, { months: 1 }) }));
51
+ }, [setStore]);
52
+
53
+ const handleYearPrev = useCallback(() => {
54
+ setStore(prev => ({
55
+ localDate: setYear(prev.localDate, prev.localDate.getFullYear() - 1),
56
+ }));
57
+ }, [setStore]);
58
+
59
+ const handleYearNext = useCallback(() => {
60
+ setStore(prev => ({
61
+ localDate: setYear(prev.localDate, prev.localDate.getFullYear() + 1),
62
+ }));
63
+ }, [setStore]);
64
+
65
+ const pickerOpen = pickerType === 'month' || pickerType === 'year';
66
+
67
+ return (
68
+ <View pointerEvents="box-none">
69
+ {isHorizontal && (
70
+ <View
71
+ style={[
72
+ datePickerHeaderStyles.datePickerHeader,
73
+ styles.row,
74
+ pickerOpen && styles.rowPickerOpen,
75
+ styleProp,
76
+ ]}>
77
+ <HeaderItem
78
+ onPrev={handleMonthPrev}
79
+ onNext={handleMonthNext}
80
+ onPressDropdown={handleMonthDropdown}
81
+ type="month"
82
+ value={monthName}
83
+ pickerType={pickerType}
84
+ selecting={pickerType === 'month'}
85
+ />
86
+ <HeaderItem
87
+ onPrev={handleYearPrev}
88
+ onNext={handleYearNext}
89
+ onPressDropdown={handleYearDropdown}
90
+ type="year"
91
+ value={year}
92
+ pickerType={pickerType}
93
+ selecting={pickerType === 'year'}
94
+ />
95
+ </View>
96
+ )}
97
+ <DayNames disableWeekDays={disableWeekDays} locale={locale} />
98
+ </View>
99
+ );
100
+ }
101
+
102
+ const styles = StyleSheet.create(theme => ({
103
+ row: {
104
+ flexDirection: 'row',
105
+ alignItems: 'center',
106
+ },
107
+ rowPickerOpen: {
108
+ borderBottomWidth: StyleSheet.hairlineWidth,
109
+ borderBottomColor: theme.colors.outlineVariant,
110
+ },
111
+ }));
112
+
113
+ export default memo(DatePickerDockedHeader);
@@ -1,18 +1,18 @@
1
- import { memo, useCallback, useMemo } from 'react';
1
+ import { memo, useCallback } from 'react';
2
2
  import { View, type ViewStyle } from 'react-native';
3
3
 
4
4
  import { useControlledValue } from '../../hooks';
5
- import type {
6
- LocalState,
7
- LocalStateMultiple,
8
- LocalStateRange,
9
- LocalStateSingle,
10
- } from '../DatePickerModal/types';
5
+ import DatePickerDockedHeader from './DatePickerDockedHeader';
11
6
  import DatePickerInlineBase from './DatePickerInlineBase';
12
7
  import DatePickerInlineHeader from './DatePickerInlineHeader';
13
- import type { DatePickerInlineBaseProps } from './types';
8
+ import type { CalendarDate, CalendarDates, DatePickerInlineBaseProps } from './types';
14
9
  import { datePickerStyles } from './utils';
15
10
 
11
+ type LocalState = LocalStateSingle | LocalStateMultiple | LocalStateRange;
12
+ type LocalStateSingle = { date: CalendarDate };
13
+ type LocalStateMultiple = { dates: CalendarDates };
14
+ type LocalStateRange = { startDate: CalendarDate; endDate: CalendarDate };
15
+
16
16
  export type DatePickerInlineProps = DatePickerInlineBaseProps & {
17
17
  containerStyle?: ViewStyle;
18
18
  };
@@ -25,6 +25,8 @@ const DatePickerInline = ({
25
25
  onChange,
26
26
  locale = 'en',
27
27
  mode = 'single',
28
+ headerLayout = 'inline',
29
+ HeaderComponent,
28
30
  containerStyle: containerStyleProp,
29
31
  ...rest
30
32
  }: DatePickerInlineProps) => {
@@ -40,16 +42,15 @@ const DatePickerInline = ({
40
42
  onChange: onInnerChange,
41
43
  });
42
44
 
43
- const { containerStyle } = useMemo(() => {
44
- return {
45
- containerStyle: [datePickerStyles.container, datePickerStyles.root, containerStyleProp],
46
- };
47
- }, [containerStyleProp]);
45
+ const resolvedHeader =
46
+ HeaderComponent ??
47
+ (headerLayout === 'docked' ? DatePickerDockedHeader : DatePickerInlineHeader);
48
48
 
49
49
  return (
50
- <View style={containerStyle}>
50
+ <View style={[datePickerStyles.container, datePickerStyles.root, containerStyleProp]}>
51
51
  <DatePickerInlineBase
52
52
  {...rest}
53
+ headerLayout={headerLayout}
53
54
  locale={locale}
54
55
  mode={mode}
55
56
  startDate={(state as LocalStateRange)?.startDate}
@@ -59,7 +60,7 @@ const DatePickerInline = ({
59
60
  dates={(state as LocalStateMultiple)?.dates}
60
61
  // TODO - fix ts issues
61
62
  // @ts-ignore
62
- HeaderComponent={DatePickerInlineHeader}
63
+ HeaderComponent={resolvedHeader}
63
64
  />
64
65
  </View>
65
66
  );
@@ -43,6 +43,8 @@ function DatePickerInlineBaseChild(props: DatePickerInlineBaseProps) {
43
43
  HeaderComponent,
44
44
  onToggle,
45
45
  monthStyle,
46
+ showOutsideDays,
47
+ headerLayout,
46
48
  } = props;
47
49
  const [pickerType, setStore] = useDatePickerStore(state => state.pickerType);
48
50
 
@@ -125,6 +127,7 @@ function DatePickerInlineBaseChild(props: DatePickerInlineBaseProps) {
125
127
  scrollMode={scrollMode}
126
128
  disableWeekDays={disableWeekDays}
127
129
  customMonthStyles={monthStyle}
130
+ showOutsideDays={showOutsideDays}
128
131
  />
129
132
  );
130
133
  },
@@ -140,6 +143,7 @@ function DatePickerInlineBaseChild(props: DatePickerInlineBaseProps) {
140
143
  scrollMode,
141
144
  disableWeekDays,
142
145
  monthStyle,
146
+ showOutsideDays,
143
147
  ],
144
148
  );
145
149
 
@@ -166,7 +170,9 @@ function DatePickerInlineBaseChild(props: DatePickerInlineBaseProps) {
166
170
  renderItem={renderMonthComponent}
167
171
  renderHeader={renderCalenderHeader}
168
172
  />
169
- {isHorizontal && pickerType === 'year' && <YearPicker />}
173
+ {isHorizontal && pickerType === 'year' && (
174
+ <YearPicker layout={headerLayout === 'docked' ? 'list' : 'grid'} />
175
+ )}
170
176
  {isHorizontal && pickerType === 'month' && <MonthPicker />}
171
177
  </View>
172
178
  );
@@ -1,11 +1,17 @@
1
1
  import { memo, useCallback, useMemo } from 'react';
2
2
  import { type StyleProp, View, type ViewStyle } from 'react-native';
3
3
 
4
+ import { useActionState } from '../../hooks/useActionState';
4
5
  import { resolveStateVariant } from '../../utils';
6
+ import { StateLayer } from '../StateLayer';
5
7
  import { Text } from '../Text';
6
8
  import { TouchableRipple } from '../TouchableRipple';
7
9
  import DayRange from './DayRange';
8
- import { datePickerDayEmptyStyles, datePickerDayStyles } from './utils';
10
+ import {
11
+ datePickerDayEmptyStyles,
12
+ datePickerDayStateLayerStyles,
13
+ datePickerDayStyles,
14
+ } from './utils';
9
15
 
10
16
  function EmptyDayPure() {
11
17
  return <View style={datePickerDayEmptyStyles.root} />;
@@ -23,6 +29,7 @@ function Day(props: {
23
29
  rightCrop: boolean;
24
30
  isToday: boolean;
25
31
  disabled: boolean;
32
+ outside?: boolean;
26
33
  onPressDate: (date: Date) => any;
27
34
  }) {
28
35
  const {
@@ -36,17 +43,32 @@ function Day(props: {
36
43
  onPressDate,
37
44
  isToday,
38
45
  disabled,
46
+ outside,
39
47
  } = props;
48
+
49
+ const { hovered, actionsRef } = useActionState({ actionsToListen: ['hover'] });
50
+
40
51
  const state = resolveStateVariant({
41
52
  disabled,
42
53
  selected,
43
54
  inRange,
44
55
  today: isToday,
56
+ outside: !!outside,
45
57
  });
46
58
  datePickerDayStyles.useVariants({
47
59
  state: state as any,
48
60
  });
49
61
 
62
+ datePickerDayStateLayerStyles.useVariants({
63
+ state: resolveStateVariant({
64
+ hovered: hovered,
65
+ outsideAndHovered: !!outside && !selected && !inRange && hovered,
66
+ selectedAndHovered: selected && hovered,
67
+ inRangeAndHovered: inRange && hovered,
68
+ todayAndHovered: isToday && hovered,
69
+ }) as any,
70
+ });
71
+
50
72
  const onPress = useCallback(() => {
51
73
  onPressDate(new Date(year, month, day));
52
74
  }, [onPressDate, year, month, day]);
@@ -69,6 +91,7 @@ function Day(props: {
69
91
  <DayRange inRange={inRange} leftCrop={leftCrop} rightCrop={rightCrop} />
70
92
 
71
93
  <TouchableRipple
94
+ ref={actionsRef}
72
95
  testID={`day-${year}-${month}-${day}`}
73
96
  disabled={disabled}
74
97
  borderless={true}
@@ -80,6 +103,7 @@ function Day(props: {
80
103
  {day}
81
104
  </Text>
82
105
  </View>
106
+ <StateLayer style={datePickerDayStateLayerStyles.stateLayer} />
83
107
  </TouchableRipple>
84
108
  </View>
85
109
  );
@@ -1,5 +1,5 @@
1
1
  import { memo } from 'react';
2
- import { StyleSheet, View } from 'react-native';
2
+ import { View } from 'react-native';
3
3
 
4
4
  import { resolveStateVariant } from '../../utils';
5
5
  import { datePickerDayRangeStyles } from './utils';
@@ -29,9 +29,7 @@ function DayRange({
29
29
  return (
30
30
  <>
31
31
  {(inRange || isCrop) && (
32
- <View
33
- pointerEvents="none"
34
- style={[StyleSheet.absoluteFill, datePickerDayRangeStyles.container]}>
32
+ <View pointerEvents="none" style={datePickerDayRangeStyles.container}>
35
33
  {isCrop && (
36
34
  <>
37
35
  <View style={datePickerDayRangeStyles.rightCrop} />
@@ -1,7 +1,8 @@
1
- import { memo, useCallback, useMemo } from 'react';
2
- import { type StyleProp, View, type ViewStyle } from 'react-native';
1
+ import { memo, useCallback } from 'react';
2
+ import { View } from 'react-native';
3
3
 
4
- import { datePickerHeaderItemStyles } from '../DatePickerDocked/utils';
4
+ import { datePickerHeaderItemStyles } from '../DatePicker/utils';
5
+ import { Icon } from '../Icon';
5
6
  import { IconButton } from '../IconButton';
6
7
  import { Text } from '../Text';
7
8
  import { TouchableRipple } from '../TouchableRipple';
@@ -42,10 +43,11 @@ function HeaderItem({
42
43
  onNext && onNext(type);
43
44
  }, [onNext, type]);
44
45
 
45
- const containerStyle = useMemo(
46
- () =>
47
- [
46
+ return (
47
+ <View
48
+ style={[
48
49
  datePickerHeaderItemStyles.buttonContainer,
50
+ // eslint-disable-next-line react-native/no-inline-styles
49
51
  {
50
52
  justifyContent: !onPressDropdown
51
53
  ? 'flex-end'
@@ -53,22 +55,23 @@ function HeaderItem({
53
55
  ? 'flex-start'
54
56
  : 'center',
55
57
  },
56
- ] as StyleProp<ViewStyle>,
57
- [onPressDropdown, onNext],
58
- );
59
-
60
- return (
61
- <View style={containerStyle} pointerEvents={'box-none'}>
62
- {!selecting && onPrev && (
63
- <View style={datePickerHeaderItemStyles.buttonWrapper}>
58
+ ]}
59
+ pointerEvents={'box-none'}>
60
+ {onPrev && (
61
+ <View
62
+ style={[
63
+ datePickerHeaderItemStyles.buttonWrapper,
64
+ // eslint-disable-next-line react-native/no-inline-styles
65
+ (selecting || disabled) && { opacity: 0 },
66
+ ]}>
64
67
  <IconButton
65
68
  type="material-community"
66
69
  name="chevron-left"
67
- size="md"
70
+ size={24}
68
71
  // Todo: Translate
69
72
  accessibilityLabel={'Previous'}
70
73
  onPress={handleOnPrevious}
71
- disabled={value === startDateYear}
74
+ disabled={value === startDateYear || selecting || disabled}
72
75
  />
73
76
  </View>
74
77
  )}
@@ -80,27 +83,39 @@ function HeaderItem({
80
83
  accessibilityLabel={`${value}`}
81
84
  style={datePickerHeaderItemStyles.buttonStyle}>
82
85
  <View style={datePickerHeaderItemStyles.innerStyle}>
83
- <Text style={datePickerHeaderItemStyles.labelStyle} selectable={false}>
86
+ <Text
87
+ style={[
88
+ datePickerHeaderItemStyles.labelStyle,
89
+ // eslint-disable-next-line react-native/no-inline-styles
90
+ disabled && { opacity: 0.5 },
91
+ ]}
92
+ selectable={false}>
84
93
  {value}
85
94
  </Text>
86
- <IconButton
87
- onPress={handlePressDropDown}
88
- name={selecting && type === pickerType ? 'menu-up' : 'menu-down'}
89
- size="sm"
90
- disabled={disabled}
91
- />
95
+ {!disabled && (
96
+ <Icon
97
+ onPress={handlePressDropDown}
98
+ name={selecting && type === pickerType ? 'menu-up' : 'menu-down'}
99
+ size={16}
100
+ />
101
+ )}
92
102
  </View>
93
103
  </TouchableRipple>
94
104
  )}
95
- {!selecting && onNext && (
96
- <View style={datePickerHeaderItemStyles.buttonWrapper}>
105
+ {onNext && (
106
+ <View
107
+ style={[
108
+ datePickerHeaderItemStyles.buttonWrapper,
109
+ // eslint-disable-next-line react-native/no-inline-styles
110
+ (selecting || disabled) && { opacity: 0 },
111
+ ]}>
97
112
  <IconButton
98
113
  name="chevron-right"
99
- size="md"
114
+ size={24}
100
115
  // Todo: Translate
101
116
  accessibilityLabel={'Next'}
102
117
  onPress={handleOnNext}
103
- disabled={value === endDateYear}
118
+ disabled={value === endDateYear || selecting || disabled}
104
119
  />
105
120
  </View>
106
121
  )}
@@ -1,9 +1,8 @@
1
- import { memo, useCallback, useMemo } from 'react';
1
+ import { memo, useMemo } from 'react';
2
2
  import { View } from 'react-native';
3
3
 
4
4
  import { format } from '../../utils/date-fns';
5
5
  import { Text } from '../Text';
6
- import { useDatePickerStoreValue } from './DatePickerContext';
7
6
  import { getCalendarHeaderHeight } from './DatePickerInlineHeader';
8
7
  import {
9
8
  addMonths,
@@ -14,6 +13,7 @@ import {
14
13
  getRealIndex,
15
14
  gridCounts,
16
15
  startAtIndex,
16
+ totalMonths,
17
17
  useRangeChecker,
18
18
  } from './dateUtils';
19
19
  import type { MonthMultiProps, MonthRangeProps, MonthSingleProps } from './types';
@@ -42,11 +42,9 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
42
42
  scrollMode,
43
43
  disableWeekDays,
44
44
  validRange,
45
+ showOutsideDays,
45
46
  // customMonthStyles,
46
47
  } = props;
47
- const { localDate } = useDatePickerStoreValue(state => ({ localDate: state.localDate }));
48
- // const monthStyles = useComponentStyles('DatePicker_Month', customMonthStyles);
49
-
50
48
  const isHorizontal = scrollMode === 'horizontal';
51
49
  const { isDisabled, isWithinValidRange } = useRangeChecker(validRange);
52
50
 
@@ -54,11 +52,11 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
54
52
  const realIndex = getRealIndex(index);
55
53
 
56
54
  const md = addMonths(new Date(), realIndex);
57
- const y = mode === 'single' ? localDate.getFullYear() : md.getFullYear();
58
- const m = mode === 'single' ? localDate.getMonth() : md.getMonth();
55
+ const y = md.getFullYear();
56
+ const m = md.getMonth();
59
57
 
60
58
  return { monthName: format(md, 'LLLL'), month: m, year: y };
61
- }, [index, localDate, mode]);
59
+ }, [index]);
62
60
 
63
61
  const grid = useMemo(
64
62
  () =>
@@ -78,67 +76,34 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
78
76
  [year, month, index, isDisabled, mode, isWithinValidRange, startDate, endDate, dates, date],
79
77
  );
80
78
 
81
- const { headerStyle, yearButtonStyle, yearInnerStyle, monthLabelStyle, weekContainerStyle } =
82
- useMemo(() => {
83
- // const {
84
- // monthLabel: _monthLabel,
85
- // yearButton,
86
- // yearButtonInner,
87
- // month: _monthStyle,
88
- // monthHeader,
89
- // dockedHeaderStyle,
90
- // weekContainerStyle: weekContainer,
91
- // } = monthStyles;
92
- // const { typescale, ...monthLabel } = _monthLabel;
93
-
94
- return {
95
- headerStyle: [
96
- datePickerMonthStyles.monthHeader,
97
- isHorizontal
98
- ? [
99
- datePickerMonthStyles.dockedHeaderStyle,
100
- {
101
- marginTop: monthHeaderSingleMarginTop,
102
- marginBottom: monthHeaderSingleMarginBottom,
103
- },
104
- ]
105
- : null,
106
- ],
107
- yearButtonStyle: datePickerMonthStyles.yearButton,
108
- yearInnerStyle: datePickerMonthStyles.yearButtonInner,
109
- monthLabelStyle: [datePickerMonthStyles.monthLabel],
110
- weekContainerStyle: datePickerMonthStyles.weekContainerStyle,
111
- };
112
- }, [isHorizontal]);
113
-
114
- const renderHeader = useCallback(() => {
115
- if (!isHorizontal) {
116
- return (
79
+ const headerStyle = [
80
+ datePickerMonthStyles.monthHeader,
81
+ isHorizontal
82
+ ? [
83
+ datePickerMonthStyles.dockedHeaderStyle,
84
+ {
85
+ marginTop: monthHeaderSingleMarginTop,
86
+ marginBottom: monthHeaderSingleMarginBottom,
87
+ },
88
+ ]
89
+ : null,
90
+ ];
91
+
92
+ return (
93
+ <View>
94
+ {!isHorizontal ? (
117
95
  <View style={headerStyle}>
118
- <View accessibilityLabel={`${monthName} ${year}`} style={yearButtonStyle}>
119
- <View style={yearInnerStyle}>
120
- <Text style={monthLabelStyle} selectable={false}>
96
+ <View
97
+ accessibilityLabel={`${monthName} ${year}`}
98
+ style={[datePickerMonthStyles.yearButton]}>
99
+ <View style={[datePickerMonthStyles.yearButtonInner]}>
100
+ <Text style={datePickerMonthStyles.monthLabel} selectable={false}>
121
101
  {monthName} {year}
122
102
  </Text>
123
103
  </View>
124
104
  </View>
125
105
  </View>
126
- );
127
- }
128
- return null;
129
- }, [
130
- headerStyle,
131
- isHorizontal,
132
- monthLabelStyle,
133
- monthName,
134
- year,
135
- yearButtonStyle,
136
- yearInnerStyle,
137
- ]);
138
-
139
- return (
140
- <View>
141
- {renderHeader()}
106
+ ) : null}
142
107
  {grid.map(({ weekIndex, generatedDays }) => (
143
108
  <Week
144
109
  key={weekIndex}
@@ -146,7 +111,8 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
146
111
  generatedDays={generatedDays}
147
112
  disableWeekDays={disableWeekDays}
148
113
  onPressDate={onPressDate}
149
- style={weekContainerStyle}
114
+ showOutsideDays={showOutsideDays}
115
+ style={datePickerMonthStyles.weekContainerStyle}
150
116
  />
151
117
  ))}
152
118
  </View>
@@ -190,7 +156,21 @@ function weeksOffset(index: number): number {
190
156
  }
191
157
 
192
158
  export function getIndexFromHorizontalOffset(offset: number, width: number): number {
193
- return startAtIndex + Math.floor(offset / width);
159
+ if (!Number.isFinite(offset) || !Number.isFinite(width) || width <= 1) {
160
+ return startAtIndex;
161
+ }
162
+
163
+ const rawIndex = startAtIndex + Math.floor(offset / width);
164
+
165
+ if (rawIndex < 0) {
166
+ return 0;
167
+ }
168
+
169
+ if (rawIndex >= totalMonths) {
170
+ return totalMonths - 1;
171
+ }
172
+
173
+ return rawIndex;
194
174
  }
195
175
 
196
176
  export function getIndexFromVerticalOffset(offset: number): number {