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

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 (87) 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/Menu/Menu.tsx +3 -18
  33. package/components/Popover/Popover.tsx +122 -145
  34. package/components/Popover/PopoverRoot.tsx +74 -0
  35. package/components/Popover/common.ts +50 -34
  36. package/components/Popover/index.ts +18 -1
  37. package/components/Popover/usePlatformMeasure.native.ts +90 -0
  38. package/components/Popover/usePlatformMeasure.ts +118 -0
  39. package/components/Popover/utils.ts +34 -0
  40. package/components/Select/Select.tsx +7 -8
  41. package/components/Select/context.tsx +72 -0
  42. package/components/Select/index.ts +1 -0
  43. package/components/Select/utils.ts +0 -71
  44. package/components/Slot/compose-refs.tsx +2 -0
  45. package/components/TimeField/TimeField.tsx +75 -0
  46. package/components/TimeField/index.tsx +6 -0
  47. package/components/TimeField/useTimeFieldState.ts +70 -0
  48. package/components/{TimePickerField/sanitizeTime.ts → TimeField/utils.ts} +77 -10
  49. package/components/TimePicker/TimePicker.tsx +53 -9
  50. package/components/TimePicker/TimePickerModal.tsx +186 -0
  51. package/components/TimePicker/context.tsx +17 -0
  52. package/components/TimePicker/index.tsx +15 -3
  53. package/components/TimePicker/utils.ts +50 -0
  54. package/hooks/useActionState.tsx +19 -8
  55. package/package.json +6 -1
  56. package/components/DatePickerDocked/DatePickerDocked.tsx +0 -30
  57. package/components/DatePickerDocked/DatePickerDockedHeader.tsx +0 -129
  58. package/components/DatePickerDocked/index.tsx +0 -17
  59. package/components/DatePickerDocked/types.ts +0 -11
  60. package/components/DatePickerDocked/utils.ts +0 -157
  61. package/components/DatePickerInput/DatePickerInput.tsx +0 -130
  62. package/components/DatePickerInput/DatePickerInputModal.tsx +0 -48
  63. package/components/DatePickerInput/DatePickerInputWithoutModal.tsx +0 -73
  64. package/components/DatePickerInput/DateRangeInput.tsx +0 -88
  65. package/components/DatePickerInput/index.tsx +0 -11
  66. package/components/DatePickerInput/types.ts +0 -26
  67. package/components/DatePickerInput/utils.ts +0 -24
  68. package/components/DatePickerModal/AnimatedCrossView.tsx +0 -94
  69. package/components/DatePickerModal/CalendarEdit.tsx +0 -140
  70. package/components/DatePickerModal/DatePickerModal.tsx +0 -85
  71. package/components/DatePickerModal/DatePickerModalContent.tsx +0 -155
  72. package/components/DatePickerModal/DatePickerModalContentHeader.tsx +0 -213
  73. package/components/DatePickerModal/DatePickerModalHeader.tsx +0 -74
  74. package/components/DatePickerModal/DatePickerModalHeaderBackground.tsx +0 -13
  75. package/components/DatePickerModal/index.tsx +0 -16
  76. package/components/DatePickerModal/types.ts +0 -92
  77. package/components/DatePickerModal/utils.ts +0 -122
  78. package/components/DateTimePicker/DateTimePicker.tsx +0 -172
  79. package/components/DateTimePicker/index.tsx +0 -10
  80. package/components/DateTimePicker/utils.ts +0 -12
  81. package/components/Popover/Popover.native.tsx +0 -185
  82. package/components/TimePickerField/TimePickerField.tsx +0 -154
  83. package/components/TimePickerField/index.tsx +0 -10
  84. package/components/TimePickerField/utils.ts +0 -94
  85. package/components/TimePickerModal/TimePickerModal.tsx +0 -119
  86. package/components/TimePickerModal/index.tsx +0 -10
  87. 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 {