@birdnet/advanced-react-dates 0.0.0-stage → 1.0.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 (267) hide show
  1. package/.babelrc +67 -0
  2. package/.eslintrc +66 -0
  3. package/.nvmrc +1 -0
  4. package/.nyc_output/4d8efcd220c2aec1f2b4ffd49d875001.json +1 -0
  5. package/.nyc_output/66d34779498a5d49bcf9d757dfc7fdb5.json +1 -0
  6. package/.nyc_output/8ca7e04140934515928bc7d4ae476b73.json +1 -0
  7. package/.nyc_output/afc270bb597bfc50e690436959c2ae54.json +1 -0
  8. package/.nycrc +19 -0
  9. package/.travis.yml +13 -0
  10. package/CHANGELOG.md +665 -0
  11. package/CLAUDE.md +56 -0
  12. package/INTHEWILD.md +9 -0
  13. package/LICENSE +21 -0
  14. package/README.md +421 -2
  15. package/constants.js +2 -0
  16. package/esm/components/CalendarDay.js +321 -0
  17. package/esm/components/CalendarIcon.js +11 -0
  18. package/esm/components/CalendarMonth.js +254 -0
  19. package/esm/components/CalendarMonthGrid.js +365 -0
  20. package/esm/components/CalendarWeek.js +11 -0
  21. package/esm/components/ChevronDown.js +11 -0
  22. package/esm/components/ChevronUp.js +11 -0
  23. package/esm/components/CloseButton.js +12 -0
  24. package/esm/components/CustomizableCalendarDay.js +341 -0
  25. package/esm/components/DateInput.js +344 -0
  26. package/esm/components/DateRangePicker.js +647 -0
  27. package/esm/components/DateRangePickerInput.js +341 -0
  28. package/esm/components/DateRangePickerInputController.js +348 -0
  29. package/esm/components/DayPicker.js +1167 -0
  30. package/esm/components/DayPickerKeyboardShortcuts.js +364 -0
  31. package/esm/components/DayPickerNavigation.js +314 -0
  32. package/esm/components/DayPickerRangeController.js +1202 -0
  33. package/esm/components/DayPickerSingleDateController.js +690 -0
  34. package/esm/components/KeyboardShortcutRow.js +69 -0
  35. package/esm/components/LeftArrow.js +11 -0
  36. package/esm/components/RightArrow.js +11 -0
  37. package/esm/components/SingleDatePicker.js +605 -0
  38. package/esm/components/SingleDatePickerInput.js +264 -0
  39. package/esm/components/SingleDatePickerInputController.js +260 -0
  40. package/esm/constants.js +28 -0
  41. package/esm/defaultPhrases.js +225 -0
  42. package/esm/index.js +20 -0
  43. package/esm/initialize.js +2 -0
  44. package/esm/shapes/AnchorDirectionShape.js +3 -0
  45. package/esm/shapes/CalendarInfoPositionShape.js +3 -0
  46. package/esm/shapes/DateRangePickerShape.js +101 -0
  47. package/esm/shapes/DayOfWeekShape.js +3 -0
  48. package/esm/shapes/DisabledShape.js +3 -0
  49. package/esm/shapes/FocusedInputShape.js +3 -0
  50. package/esm/shapes/IconPositionShape.js +3 -0
  51. package/esm/shapes/ModifiersShape.js +18 -0
  52. package/esm/shapes/NavPositionShape.js +3 -0
  53. package/esm/shapes/OpenDirectionShape.js +3 -0
  54. package/esm/shapes/OrientationShape.js +3 -0
  55. package/esm/shapes/ScrollableOrientationShape.js +3 -0
  56. package/esm/shapes/SingleDatePickerShape.js +90 -0
  57. package/esm/theme/DefaultTheme.js +176 -0
  58. package/esm/utils/calculateDimension.js +28 -0
  59. package/esm/utils/disableScroll.js +67 -0
  60. package/esm/utils/getActiveElement.js +3 -0
  61. package/esm/utils/getCalendarDaySettings.js +48 -0
  62. package/esm/utils/getCalendarMonthWeeks.js +37 -0
  63. package/esm/utils/getCalendarMonthWidth.js +4 -0
  64. package/esm/utils/getDetachedContainerStyles.js +36 -0
  65. package/esm/utils/getInputHeight.js +42 -0
  66. package/esm/utils/getNumberOfCalendarMonthWeeks.js +11 -0
  67. package/esm/utils/getPhrase.js +7 -0
  68. package/esm/utils/getPhrasePropTypes.js +9 -0
  69. package/esm/utils/getPooledMoment.js +8 -0
  70. package/esm/utils/getPreviousMonthMemoLast.js +9 -0
  71. package/esm/utils/getResponsiveContainerStyles.js +8 -0
  72. package/esm/utils/getSelectedDateOffset.js +8 -0
  73. package/esm/utils/getTransformStyles.js +8 -0
  74. package/esm/utils/getVisibleDays.js +42 -0
  75. package/esm/utils/isAfterDay.js +7 -0
  76. package/esm/utils/isBeforeDay.js +13 -0
  77. package/esm/utils/isDayVisible.js +38 -0
  78. package/esm/utils/isInclusivelyAfterDay.js +6 -0
  79. package/esm/utils/isInclusivelyBeforeDay.js +6 -0
  80. package/esm/utils/isNextDay.js +7 -0
  81. package/esm/utils/isNextMonth.js +6 -0
  82. package/esm/utils/isPrevMonth.js +6 -0
  83. package/esm/utils/isPreviousDay.js +7 -0
  84. package/esm/utils/isSameDay.js +7 -0
  85. package/esm/utils/isSameMonth.js +7 -0
  86. package/esm/utils/isTransitionEndSupported.js +3 -0
  87. package/esm/utils/modifiers.js +94 -0
  88. package/esm/utils/noflip.js +10 -0
  89. package/esm/utils/registerCSSInterfaceWithDefaultTheme.js +5 -0
  90. package/esm/utils/registerInterfaceWithDefaultTheme.js +6 -0
  91. package/esm/utils/toISODateString.js +12 -0
  92. package/esm/utils/toISOMonthString.js +12 -0
  93. package/esm/utils/toLocalizedDateString.js +8 -0
  94. package/esm/utils/toMomentObject.js +7 -0
  95. package/index.js +2 -0
  96. package/initialize.js +2 -0
  97. package/karma.conf.js +82 -0
  98. package/lib/components/CalendarDay.js +327 -0
  99. package/lib/components/CalendarIcon.js +18 -0
  100. package/lib/components/CalendarMonth.js +259 -0
  101. package/lib/components/CalendarMonthGrid.js +372 -0
  102. package/lib/components/CalendarWeek.js +18 -0
  103. package/lib/components/ChevronDown.js +18 -0
  104. package/lib/components/ChevronUp.js +18 -0
  105. package/lib/components/CloseButton.js +19 -0
  106. package/lib/components/CustomizableCalendarDay.js +347 -0
  107. package/lib/components/DateInput.js +351 -0
  108. package/lib/components/DateRangePicker.js +653 -0
  109. package/lib/components/DateRangePickerInput.js +348 -0
  110. package/lib/components/DateRangePickerInputController.js +354 -0
  111. package/lib/components/DayPicker.js +1175 -0
  112. package/lib/components/DayPickerKeyboardShortcuts.js +371 -0
  113. package/lib/components/DayPickerNavigation.js +321 -0
  114. package/lib/components/DayPickerRangeController.js +1208 -0
  115. package/lib/components/DayPickerSingleDateController.js +695 -0
  116. package/lib/components/KeyboardShortcutRow.js +76 -0
  117. package/lib/components/LeftArrow.js +18 -0
  118. package/lib/components/RightArrow.js +18 -0
  119. package/lib/components/SingleDatePicker.js +611 -0
  120. package/lib/components/SingleDatePickerInput.js +271 -0
  121. package/lib/components/SingleDatePickerInputController.js +266 -0
  122. package/lib/constants.js +34 -0
  123. package/lib/css/_datepicker.css +886 -0
  124. package/lib/defaultPhrases.js +231 -0
  125. package/lib/index.js +146 -0
  126. package/lib/initialize.js +5 -0
  127. package/lib/shapes/AnchorDirectionShape.js +10 -0
  128. package/lib/shapes/CalendarInfoPositionShape.js +10 -0
  129. package/lib/shapes/DateRangePickerShape.js +108 -0
  130. package/lib/shapes/DayOfWeekShape.js +10 -0
  131. package/lib/shapes/DisabledShape.js +10 -0
  132. package/lib/shapes/FocusedInputShape.js +10 -0
  133. package/lib/shapes/IconPositionShape.js +10 -0
  134. package/lib/shapes/ModifiersShape.js +25 -0
  135. package/lib/shapes/NavPositionShape.js +10 -0
  136. package/lib/shapes/OpenDirectionShape.js +10 -0
  137. package/lib/shapes/OrientationShape.js +10 -0
  138. package/lib/shapes/ScrollableOrientationShape.js +10 -0
  139. package/lib/shapes/SingleDatePickerShape.js +97 -0
  140. package/lib/theme/DefaultTheme.js +182 -0
  141. package/lib/utils/calculateDimension.js +34 -0
  142. package/lib/utils/disableScroll.js +75 -0
  143. package/lib/utils/getActiveElement.js +9 -0
  144. package/lib/utils/getCalendarDaySettings.js +55 -0
  145. package/lib/utils/getCalendarMonthWeeks.js +44 -0
  146. package/lib/utils/getCalendarMonthWidth.js +10 -0
  147. package/lib/utils/getDetachedContainerStyles.js +41 -0
  148. package/lib/utils/getInputHeight.js +48 -0
  149. package/lib/utils/getNumberOfCalendarMonthWeeks.js +18 -0
  150. package/lib/utils/getPhrase.js +13 -0
  151. package/lib/utils/getPhrasePropTypes.js +16 -0
  152. package/lib/utils/getPooledMoment.js +15 -0
  153. package/lib/utils/getPreviousMonthMemoLast.js +15 -0
  154. package/lib/utils/getResponsiveContainerStyles.js +15 -0
  155. package/lib/utils/getSelectedDateOffset.js +14 -0
  156. package/lib/utils/getTransformStyles.js +14 -0
  157. package/lib/utils/getVisibleDays.js +49 -0
  158. package/lib/utils/isAfterDay.js +14 -0
  159. package/lib/utils/isBeforeDay.js +20 -0
  160. package/lib/utils/isDayVisible.js +45 -0
  161. package/lib/utils/isInclusivelyAfterDay.js +13 -0
  162. package/lib/utils/isInclusivelyBeforeDay.js +13 -0
  163. package/lib/utils/isNextDay.js +14 -0
  164. package/lib/utils/isNextMonth.js +13 -0
  165. package/lib/utils/isPrevMonth.js +13 -0
  166. package/lib/utils/isPreviousDay.js +14 -0
  167. package/lib/utils/isSameDay.js +14 -0
  168. package/lib/utils/isSameMonth.js +14 -0
  169. package/lib/utils/isTransitionEndSupported.js +9 -0
  170. package/lib/utils/modifiers.js +102 -0
  171. package/lib/utils/noflip.js +16 -0
  172. package/lib/utils/registerCSSInterfaceWithDefaultTheme.js +12 -0
  173. package/lib/utils/registerInterfaceWithDefaultTheme.js +13 -0
  174. package/lib/utils/toISODateString.js +19 -0
  175. package/lib/utils/toISOMonthString.js +19 -0
  176. package/lib/utils/toLocalizedDateString.js +15 -0
  177. package/lib/utils/toMomentObject.js +14 -0
  178. package/package.json +141 -4
  179. package/scripts/.eslintrc +7 -0
  180. package/scripts/buildCSS.js +37 -0
  181. package/scripts/pure-component-fallback.js +70 -0
  182. package/scripts/renderAllComponents.jsx +25 -0
  183. package/src/components/CalendarDay.jsx +366 -0
  184. package/src/components/CalendarIcon.jsx +3 -0
  185. package/src/components/CalendarMonth.jsx +300 -0
  186. package/src/components/CalendarMonthGrid.jsx +427 -0
  187. package/src/components/CalendarWeek.jsx +17 -0
  188. package/src/components/ChevronDown.jsx +3 -0
  189. package/src/components/ChevronUp.jsx +3 -0
  190. package/src/components/CloseButton.jsx +3 -0
  191. package/src/components/CustomizableCalendarDay.jsx +382 -0
  192. package/src/components/DateInput.jsx +401 -0
  193. package/src/components/DateRangePicker.jsx +777 -0
  194. package/src/components/DateRangePickerInput.jsx +434 -0
  195. package/src/components/DateRangePickerInputController.jsx +379 -0
  196. package/src/components/DayPicker.jsx +1407 -0
  197. package/src/components/DayPickerKeyboardShortcuts.jsx +443 -0
  198. package/src/components/DayPickerNavigation.jsx +445 -0
  199. package/src/components/DayPickerRangeController.jsx +1409 -0
  200. package/src/components/DayPickerSingleDateController.jsx +769 -0
  201. package/src/components/KeyboardShortcutRow.jsx +93 -0
  202. package/src/components/LeftArrow.jsx +3 -0
  203. package/src/components/RightArrow.jsx +3 -0
  204. package/src/components/SingleDatePicker.jsx +731 -0
  205. package/src/components/SingleDatePickerInput.jsx +329 -0
  206. package/src/components/SingleDatePickerInputController.jsx +280 -0
  207. package/src/constants.js +37 -0
  208. package/src/defaultPhrases.js +215 -0
  209. package/src/index.js +20 -0
  210. package/src/initialize.js +3 -0
  211. package/src/shapes/AnchorDirectionShape.js +8 -0
  212. package/src/shapes/CalendarInfoPositionShape.js +15 -0
  213. package/src/shapes/DateRangePickerShape.js +111 -0
  214. package/src/shapes/DayOfWeekShape.js +5 -0
  215. package/src/shapes/DisabledShape.js +5 -0
  216. package/src/shapes/FocusedInputShape.js +8 -0
  217. package/src/shapes/IconPositionShape.js +8 -0
  218. package/src/shapes/ModifiersShape.js +20 -0
  219. package/src/shapes/NavPositionShape.js +8 -0
  220. package/src/shapes/OpenDirectionShape.js +8 -0
  221. package/src/shapes/OrientationShape.js +8 -0
  222. package/src/shapes/ScrollableOrientationShape.js +13 -0
  223. package/src/shapes/SingleDatePickerShape.js +100 -0
  224. package/src/svg/arrow-left.svg +1 -0
  225. package/src/svg/arrow-right.svg +1 -0
  226. package/src/svg/calendar.svg +1 -0
  227. package/src/svg/chevron-down.svg +1 -0
  228. package/src/svg/chevron-up.svg +1 -0
  229. package/src/svg/close.svg +1 -0
  230. package/src/theme/DefaultTheme.js +196 -0
  231. package/src/utils/calculateDimension.js +32 -0
  232. package/src/utils/disableScroll.js +65 -0
  233. package/src/utils/getActiveElement.js +3 -0
  234. package/src/utils/getCalendarDaySettings.js +61 -0
  235. package/src/utils/getCalendarMonthWeeks.js +49 -0
  236. package/src/utils/getCalendarMonthWidth.js +3 -0
  237. package/src/utils/getDetachedContainerStyles.js +39 -0
  238. package/src/utils/getInputHeight.js +67 -0
  239. package/src/utils/getNumberOfCalendarMonthWeeks.js +15 -0
  240. package/src/utils/getPhrase.jsx +9 -0
  241. package/src/utils/getPhrasePropTypes.js +9 -0
  242. package/src/utils/getPooledMoment.js +10 -0
  243. package/src/utils/getPreviousMonthMemoLast.js +11 -0
  244. package/src/utils/getResponsiveContainerStyles.js +18 -0
  245. package/src/utils/getSelectedDateOffset.js +6 -0
  246. package/src/utils/getTransformStyles.js +8 -0
  247. package/src/utils/getVisibleDays.js +54 -0
  248. package/src/utils/isAfterDay.js +9 -0
  249. package/src/utils/isBeforeDay.js +18 -0
  250. package/src/utils/isDayVisible.js +57 -0
  251. package/src/utils/isInclusivelyAfterDay.js +8 -0
  252. package/src/utils/isInclusivelyBeforeDay.js +8 -0
  253. package/src/utils/isNextDay.js +9 -0
  254. package/src/utils/isNextMonth.js +8 -0
  255. package/src/utils/isPrevMonth.js +8 -0
  256. package/src/utils/isPreviousDay.js +9 -0
  257. package/src/utils/isSameDay.js +10 -0
  258. package/src/utils/isSameMonth.js +9 -0
  259. package/src/utils/isTransitionEndSupported.js +3 -0
  260. package/src/utils/modifiers.js +116 -0
  261. package/src/utils/noflip.js +11 -0
  262. package/src/utils/registerCSSInterfaceWithDefaultTheme.js +7 -0
  263. package/src/utils/registerInterfaceWithDefaultTheme.js +7 -0
  264. package/src/utils/toISODateString.js +14 -0
  265. package/src/utils/toISOMonthString.js +14 -0
  266. package/src/utils/toLocalizedDateString.js +12 -0
  267. package/src/utils/toMomentObject.js +12 -0
@@ -0,0 +1,769 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import momentPropTypes from 'react-moment-proptypes';
4
+ import { forbidExtraProps, mutuallyExclusiveProps, nonNegativeInteger } from 'airbnb-prop-types';
5
+ import moment from 'moment';
6
+ import values from 'object.values';
7
+ import isTouchDevice from 'is-touch-device';
8
+
9
+ import { DayPickerPhrases } from '../defaultPhrases';
10
+ import getPhrasePropTypes from '../utils/getPhrasePropTypes';
11
+
12
+ import isSameDay from '../utils/isSameDay';
13
+ import isAfterDay from '../utils/isAfterDay';
14
+ import isDayVisible from '../utils/isDayVisible';
15
+
16
+ import getVisibleDays from '../utils/getVisibleDays';
17
+
18
+ import toISODateString from '../utils/toISODateString';
19
+ import { addModifier, deleteModifier } from '../utils/modifiers';
20
+
21
+ import ScrollableOrientationShape from '../shapes/ScrollableOrientationShape';
22
+ import DayOfWeekShape from '../shapes/DayOfWeekShape';
23
+ import CalendarInfoPositionShape from '../shapes/CalendarInfoPositionShape';
24
+ import NavPositionShape from '../shapes/NavPositionShape';
25
+
26
+ import {
27
+ HORIZONTAL_ORIENTATION,
28
+ VERTICAL_SCROLLABLE,
29
+ DAY_SIZE,
30
+ INFO_POSITION_BOTTOM,
31
+ NAV_POSITION_TOP,
32
+ } from '../constants';
33
+
34
+ import DayPicker from './DayPicker';
35
+ import getPooledMoment from '../utils/getPooledMoment';
36
+
37
+ // Default value of the date property. Represents the state
38
+ // when there is no date selected.
39
+ // TODO: use null
40
+ const DATE_UNSET_VALUE = undefined;
41
+
42
+ const propTypes = forbidExtraProps({
43
+ date: momentPropTypes.momentObj,
44
+ minDate: momentPropTypes.momentObj,
45
+ maxDate: momentPropTypes.momentObj,
46
+ onDateChange: PropTypes.func,
47
+
48
+ allowUnselect: PropTypes.bool,
49
+ focused: PropTypes.bool,
50
+ onFocusChange: PropTypes.func,
51
+ onClose: PropTypes.func,
52
+
53
+ keepOpenOnDateSelect: PropTypes.bool,
54
+ isOutsideRange: PropTypes.func,
55
+ isDayBlocked: PropTypes.func,
56
+ isDayHighlighted: PropTypes.func,
57
+
58
+ // DayPicker props
59
+ renderMonthText: mutuallyExclusiveProps(PropTypes.func, 'renderMonthText', 'renderMonthElement'),
60
+ renderMonthElement: mutuallyExclusiveProps(PropTypes.func, 'renderMonthText', 'renderMonthElement'),
61
+ renderWeekHeaderElement: PropTypes.func,
62
+ enableOutsideDays: PropTypes.bool,
63
+ numberOfMonths: PropTypes.number,
64
+ orientation: ScrollableOrientationShape,
65
+ withPortal: PropTypes.bool,
66
+ initialVisibleMonth: PropTypes.func,
67
+ firstDayOfWeek: DayOfWeekShape,
68
+ hideKeyboardShortcutsPanel: PropTypes.bool,
69
+ daySize: nonNegativeInteger,
70
+ verticalHeight: nonNegativeInteger,
71
+ noBorder: PropTypes.bool,
72
+ verticalBorderSpacing: nonNegativeInteger,
73
+ transitionDuration: nonNegativeInteger,
74
+ horizontalMonthPadding: nonNegativeInteger,
75
+
76
+ dayPickerNavigationInlineStyles: PropTypes.object,
77
+ navPosition: NavPositionShape,
78
+ navPrev: PropTypes.node,
79
+ navNext: PropTypes.node,
80
+ renderNavPrevButton: PropTypes.func,
81
+ renderNavNextButton: PropTypes.func,
82
+ noNavButtons: PropTypes.bool,
83
+ noNavNextButton: PropTypes.bool,
84
+ noNavPrevButton: PropTypes.bool,
85
+
86
+ onPrevMonthClick: PropTypes.func,
87
+ onNextMonthClick: PropTypes.func,
88
+ onOutsideClick: PropTypes.func,
89
+ renderCalendarDay: PropTypes.func,
90
+ renderDayContents: PropTypes.func,
91
+ renderCalendarInfo: PropTypes.func,
92
+ calendarInfoPosition: CalendarInfoPositionShape,
93
+
94
+ // accessibility
95
+ onBlur: PropTypes.func,
96
+ isFocused: PropTypes.bool,
97
+ showKeyboardShortcuts: PropTypes.bool,
98
+ onTab: PropTypes.func,
99
+ onShiftTab: PropTypes.func,
100
+
101
+ // i18n
102
+ monthFormat: PropTypes.string,
103
+ weekDayFormat: PropTypes.string,
104
+ phrases: PropTypes.shape(getPhrasePropTypes(DayPickerPhrases)),
105
+ dayAriaLabelFormat: PropTypes.string,
106
+
107
+ isRTL: PropTypes.bool,
108
+ });
109
+
110
+ const defaultProps = {
111
+ date: DATE_UNSET_VALUE,
112
+ minDate: null,
113
+ maxDate: null,
114
+ onDateChange() {},
115
+
116
+ allowUnselect: false,
117
+ focused: false,
118
+ onFocusChange() {},
119
+ onClose() {},
120
+
121
+ keepOpenOnDateSelect: false,
122
+ isOutsideRange() {},
123
+ isDayBlocked() {},
124
+ isDayHighlighted() {},
125
+
126
+ // DayPicker props
127
+ renderMonthText: null,
128
+ renderWeekHeaderElement: null,
129
+ enableOutsideDays: false,
130
+ numberOfMonths: 1,
131
+ orientation: HORIZONTAL_ORIENTATION,
132
+ withPortal: false,
133
+ hideKeyboardShortcutsPanel: false,
134
+ initialVisibleMonth: null,
135
+ firstDayOfWeek: null,
136
+ daySize: DAY_SIZE,
137
+ verticalHeight: null,
138
+ noBorder: false,
139
+ verticalBorderSpacing: undefined,
140
+ transitionDuration: undefined,
141
+ horizontalMonthPadding: 13,
142
+
143
+ dayPickerNavigationInlineStyles: null,
144
+ navPosition: NAV_POSITION_TOP,
145
+ navPrev: null,
146
+ navNext: null,
147
+ renderNavPrevButton: null,
148
+ renderNavNextButton: null,
149
+ noNavButtons: false,
150
+ noNavNextButton: false,
151
+ noNavPrevButton: false,
152
+
153
+ onPrevMonthClick() {},
154
+ onNextMonthClick() {},
155
+ onOutsideClick() {},
156
+
157
+ renderCalendarDay: undefined,
158
+ renderDayContents: null,
159
+ renderCalendarInfo: null,
160
+ renderMonthElement: null,
161
+ calendarInfoPosition: INFO_POSITION_BOTTOM,
162
+
163
+ // accessibility
164
+ onBlur() {},
165
+ isFocused: false,
166
+ showKeyboardShortcuts: false,
167
+ onTab() {},
168
+ onShiftTab() {},
169
+
170
+ // i18n
171
+ monthFormat: 'MMMM YYYY',
172
+ weekDayFormat: 'dd',
173
+ phrases: DayPickerPhrases,
174
+ dayAriaLabelFormat: undefined,
175
+
176
+ isRTL: false,
177
+ };
178
+
179
+ export default class DayPickerSingleDateController extends React.PureComponent {
180
+ constructor(props) {
181
+ super(props);
182
+
183
+ this.isTouchDevice = false;
184
+ this.today = moment();
185
+
186
+ this.modifiers = {
187
+ today: (day) => this.isToday(day),
188
+ blocked: (day) => this.isBlocked(day),
189
+ 'blocked-calendar': (day) => props.isDayBlocked(day),
190
+ 'blocked-out-of-range': (day) => props.isOutsideRange(day),
191
+ 'highlighted-calendar': (day) => props.isDayHighlighted(day),
192
+ valid: (day) => !this.isBlocked(day),
193
+ hovered: (day) => this.isHovered(day),
194
+ selected: (day) => this.isSelected(day),
195
+ 'first-day-of-week': (day) => this.isFirstDayOfWeek(day),
196
+ 'last-day-of-week': (day) => this.isLastDayOfWeek(day),
197
+ };
198
+
199
+ const { currentMonth, visibleDays } = this.getStateForNewMonth(props);
200
+
201
+ this.state = {
202
+ hoverDate: null,
203
+ currentMonth,
204
+ visibleDays,
205
+ disablePrev: this.shouldDisableMonthNavigation(props.minDate, currentMonth),
206
+ disableNext: this.shouldDisableMonthNavigation(props.maxDate, currentMonth),
207
+ };
208
+
209
+ this.onDayMouseEnter = this.onDayMouseEnter.bind(this);
210
+ this.onDayMouseLeave = this.onDayMouseLeave.bind(this);
211
+ this.onDayClick = this.onDayClick.bind(this);
212
+
213
+ this.onPrevMonthClick = this.onPrevMonthClick.bind(this);
214
+ this.onNextMonthClick = this.onNextMonthClick.bind(this);
215
+ this.onMonthChange = this.onMonthChange.bind(this);
216
+ this.onYearChange = this.onYearChange.bind(this);
217
+ this.onGetNextScrollableMonths = this.onGetNextScrollableMonths.bind(this);
218
+ this.onGetPrevScrollableMonths = this.onGetPrevScrollableMonths.bind(this);
219
+ this.getFirstFocusableDay = this.getFirstFocusableDay.bind(this);
220
+ }
221
+
222
+ componentDidMount() {
223
+ this.isTouchDevice = isTouchDevice();
224
+ }
225
+
226
+ componentDidUpdate(prevProps) {
227
+ const {
228
+ date,
229
+ focused,
230
+ isOutsideRange,
231
+ isDayBlocked,
232
+ isDayHighlighted,
233
+ initialVisibleMonth,
234
+ numberOfMonths,
235
+ enableOutsideDays,
236
+ } = this.props;
237
+ const {
238
+ isOutsideRange: prevIsOutsideRange,
239
+ isDayBlocked: prevIsDayBlocked,
240
+ isDayHighlighted: prevIsDayHighlighted,
241
+ numberOfMonths: prevNumberOfMonths,
242
+ enableOutsideDays: prevEnableOutsideDays,
243
+ initialVisibleMonth: prevInitialVisibleMonth,
244
+ focused: prevFocused,
245
+ date: prevDate,
246
+ } = prevProps;
247
+ let { visibleDays } = this.state;
248
+
249
+ let recomputeOutsideRange = false;
250
+ let recomputeDayBlocked = false;
251
+ let recomputeDayHighlighted = false;
252
+
253
+ if (isOutsideRange !== prevIsOutsideRange) {
254
+ this.modifiers['blocked-out-of-range'] = (day) => isOutsideRange(day);
255
+ recomputeOutsideRange = true;
256
+ }
257
+
258
+ if (isDayBlocked !== prevIsDayBlocked) {
259
+ this.modifiers['blocked-calendar'] = (day) => isDayBlocked(day);
260
+ recomputeDayBlocked = true;
261
+ }
262
+
263
+ if (isDayHighlighted !== prevIsDayHighlighted) {
264
+ this.modifiers['highlighted-calendar'] = (day) => isDayHighlighted(day);
265
+ recomputeDayHighlighted = true;
266
+ }
267
+
268
+ const recomputePropModifiers = (
269
+ recomputeOutsideRange || recomputeDayBlocked || recomputeDayHighlighted
270
+ );
271
+ const { currentMonth: prevCurrentMonth } = this.state;
272
+
273
+ if (
274
+ numberOfMonths !== prevNumberOfMonths
275
+ || enableOutsideDays !== prevEnableOutsideDays
276
+ || (
277
+ initialVisibleMonth !== prevInitialVisibleMonth
278
+ && !prevFocused
279
+ && focused
280
+ )
281
+ || (
282
+ prevDate
283
+ && prevDate.diff(date)
284
+ && !isDayVisible(date, prevCurrentMonth, numberOfMonths)
285
+ )
286
+ ) {
287
+ const newMonthState = this.getStateForNewMonth(this.props);
288
+ const { currentMonth } = newMonthState;
289
+ ({ visibleDays } = newMonthState);
290
+ this.setState({
291
+ currentMonth,
292
+ visibleDays,
293
+ });
294
+ }
295
+
296
+ const didDateChange = date !== prevDate;
297
+ const didFocusChange = focused !== prevFocused;
298
+
299
+ let modifiers = {};
300
+
301
+ if (didDateChange) {
302
+ modifiers = this.deleteModifier(modifiers, prevDate, 'selected');
303
+ modifiers = this.addModifier(modifiers, date, 'selected');
304
+ }
305
+
306
+ if (didFocusChange || recomputePropModifiers) {
307
+ values(visibleDays).forEach((days) => {
308
+ Object.keys(days).forEach((day) => {
309
+ const momentObj = getPooledMoment(day);
310
+ if (this.isBlocked(momentObj)) {
311
+ modifiers = this.addModifier(modifiers, momentObj, 'blocked');
312
+ } else {
313
+ modifiers = this.deleteModifier(modifiers, momentObj, 'blocked');
314
+ }
315
+
316
+ if (didFocusChange || recomputeOutsideRange) {
317
+ if (isOutsideRange(momentObj)) {
318
+ modifiers = this.addModifier(modifiers, momentObj, 'blocked-out-of-range');
319
+ } else {
320
+ modifiers = this.deleteModifier(modifiers, momentObj, 'blocked-out-of-range');
321
+ }
322
+ }
323
+
324
+ if (didFocusChange || recomputeDayBlocked) {
325
+ if (isDayBlocked(momentObj)) {
326
+ modifiers = this.addModifier(modifiers, momentObj, 'blocked-calendar');
327
+ } else {
328
+ modifiers = this.deleteModifier(modifiers, momentObj, 'blocked-calendar');
329
+ }
330
+ }
331
+
332
+ if (didFocusChange || recomputeDayHighlighted) {
333
+ if (isDayHighlighted(momentObj)) {
334
+ modifiers = this.addModifier(modifiers, momentObj, 'highlighted-calendar');
335
+ } else {
336
+ modifiers = this.deleteModifier(modifiers, momentObj, 'highlighted-calendar');
337
+ }
338
+ }
339
+ });
340
+ });
341
+ }
342
+
343
+ const today = moment();
344
+ if (!isSameDay(this.today, today)) {
345
+ modifiers = this.deleteModifier(modifiers, this.today, 'today');
346
+ modifiers = this.addModifier(modifiers, today, 'today');
347
+ this.today = today;
348
+ }
349
+
350
+ if (Object.keys(modifiers).length > 0) {
351
+ this.setState({
352
+ visibleDays: {
353
+ ...visibleDays,
354
+ ...modifiers,
355
+ },
356
+ });
357
+ }
358
+ }
359
+
360
+ onDayClick(day, e) {
361
+ if (e) e.preventDefault();
362
+ if (this.isBlocked(day)) return;
363
+ const {
364
+ allowUnselect,
365
+ onDateChange,
366
+ keepOpenOnDateSelect,
367
+ onFocusChange,
368
+ onClose,
369
+ } = this.props;
370
+
371
+ const clickedDay = allowUnselect && this.isSelected(day) ? DATE_UNSET_VALUE : day;
372
+
373
+ onDateChange(clickedDay);
374
+ if (!keepOpenOnDateSelect) {
375
+ onFocusChange({ focused: false });
376
+ onClose({ date: clickedDay });
377
+ }
378
+ }
379
+
380
+ onDayMouseEnter(day) {
381
+ if (this.isTouchDevice) return;
382
+ const { hoverDate, visibleDays } = this.state;
383
+
384
+ let modifiers = this.deleteModifier({}, hoverDate, 'hovered');
385
+ modifiers = this.addModifier(modifiers, day, 'hovered');
386
+
387
+ this.setState({
388
+ hoverDate: day,
389
+ visibleDays: {
390
+ ...visibleDays,
391
+ ...modifiers,
392
+ },
393
+ });
394
+ }
395
+
396
+ onDayMouseLeave() {
397
+ const { hoverDate, visibleDays } = this.state;
398
+ if (this.isTouchDevice || !hoverDate) return;
399
+
400
+ const modifiers = this.deleteModifier({}, hoverDate, 'hovered');
401
+
402
+ this.setState({
403
+ hoverDate: null,
404
+ visibleDays: {
405
+ ...visibleDays,
406
+ ...modifiers,
407
+ },
408
+ });
409
+ }
410
+
411
+ onPrevMonthClick() {
412
+ const {
413
+ enableOutsideDays,
414
+ maxDate,
415
+ minDate,
416
+ numberOfMonths,
417
+ onPrevMonthClick,
418
+ } = this.props;
419
+ const { currentMonth, visibleDays } = this.state;
420
+
421
+ const newVisibleDays = {};
422
+ Object.keys(visibleDays).sort().slice(0, numberOfMonths + 1).forEach((month) => {
423
+ newVisibleDays[month] = visibleDays[month];
424
+ });
425
+
426
+ const prevMonth = currentMonth.clone().subtract(1, 'month');
427
+ const prevMonthVisibleDays = getVisibleDays(prevMonth, 1, enableOutsideDays);
428
+ const newCurrentMonth = currentMonth.clone().subtract(1, 'month');
429
+
430
+ this.setState({
431
+ currentMonth: prevMonth,
432
+ disablePrev: this.shouldDisableMonthNavigation(minDate, newCurrentMonth),
433
+ disableNext: this.shouldDisableMonthNavigation(maxDate, newCurrentMonth),
434
+ visibleDays: {
435
+ ...newVisibleDays,
436
+ ...this.getModifiers(prevMonthVisibleDays),
437
+ },
438
+ }, () => {
439
+ onPrevMonthClick(prevMonth.clone());
440
+ });
441
+ }
442
+
443
+ onNextMonthClick() {
444
+ const {
445
+ enableOutsideDays,
446
+ maxDate,
447
+ minDate,
448
+ numberOfMonths,
449
+ onNextMonthClick,
450
+ } = this.props;
451
+ const { currentMonth, visibleDays } = this.state;
452
+
453
+ const newVisibleDays = {};
454
+ Object.keys(visibleDays).sort().slice(1).forEach((month) => {
455
+ newVisibleDays[month] = visibleDays[month];
456
+ });
457
+
458
+ const nextMonth = currentMonth.clone().add(numberOfMonths, 'month');
459
+ const nextMonthVisibleDays = getVisibleDays(nextMonth, 1, enableOutsideDays);
460
+
461
+ const newCurrentMonth = currentMonth.clone().add(1, 'month');
462
+ this.setState({
463
+ currentMonth: newCurrentMonth,
464
+ disablePrev: this.shouldDisableMonthNavigation(minDate, newCurrentMonth),
465
+ disableNext: this.shouldDisableMonthNavigation(maxDate, newCurrentMonth),
466
+ visibleDays: {
467
+ ...newVisibleDays,
468
+ ...this.getModifiers(nextMonthVisibleDays),
469
+ },
470
+ }, () => {
471
+ onNextMonthClick(newCurrentMonth.clone());
472
+ });
473
+ }
474
+
475
+ onMonthChange(newMonth) {
476
+ const { numberOfMonths, enableOutsideDays, orientation } = this.props;
477
+ const withoutTransitionMonths = orientation === VERTICAL_SCROLLABLE;
478
+ const newVisibleDays = getVisibleDays(
479
+ newMonth,
480
+ numberOfMonths,
481
+ enableOutsideDays,
482
+ withoutTransitionMonths,
483
+ );
484
+
485
+ this.setState({
486
+ currentMonth: newMonth.clone(),
487
+ visibleDays: this.getModifiers(newVisibleDays),
488
+ });
489
+ }
490
+
491
+ onYearChange(newMonth) {
492
+ const { numberOfMonths, enableOutsideDays, orientation } = this.props;
493
+ const withoutTransitionMonths = orientation === VERTICAL_SCROLLABLE;
494
+ const newVisibleDays = getVisibleDays(
495
+ newMonth,
496
+ numberOfMonths,
497
+ enableOutsideDays,
498
+ withoutTransitionMonths,
499
+ );
500
+
501
+ this.setState({
502
+ currentMonth: newMonth.clone(),
503
+ visibleDays: this.getModifiers(newVisibleDays),
504
+ });
505
+ }
506
+
507
+ onGetNextScrollableMonths() {
508
+ const { numberOfMonths, enableOutsideDays } = this.props;
509
+ const { currentMonth, visibleDays } = this.state;
510
+
511
+ const numberOfVisibleMonths = Object.keys(visibleDays).length;
512
+ const nextMonth = currentMonth.clone().add(numberOfVisibleMonths, 'month');
513
+ const newVisibleDays = getVisibleDays(nextMonth, numberOfMonths, enableOutsideDays, true);
514
+
515
+ this.setState({
516
+ visibleDays: {
517
+ ...visibleDays,
518
+ ...this.getModifiers(newVisibleDays),
519
+ },
520
+ });
521
+ }
522
+
523
+ onGetPrevScrollableMonths() {
524
+ const { numberOfMonths, enableOutsideDays } = this.props;
525
+ const { currentMonth, visibleDays } = this.state;
526
+
527
+ const firstPreviousMonth = currentMonth.clone().subtract(numberOfMonths, 'month');
528
+ const newVisibleDays = getVisibleDays(firstPreviousMonth, numberOfMonths, enableOutsideDays, true);
529
+
530
+ this.setState({
531
+ currentMonth: firstPreviousMonth.clone(),
532
+ visibleDays: {
533
+ ...visibleDays,
534
+ ...this.getModifiers(newVisibleDays),
535
+ },
536
+ });
537
+ }
538
+
539
+ getFirstDayOfWeek() {
540
+ const { firstDayOfWeek } = this.props;
541
+ if (firstDayOfWeek == null) {
542
+ return moment.localeData().firstDayOfWeek();
543
+ }
544
+
545
+ return firstDayOfWeek;
546
+ }
547
+
548
+ getFirstFocusableDay(newMonth) {
549
+ const { date, numberOfMonths } = this.props;
550
+
551
+ let focusedDate = newMonth.clone().startOf('month').hour(12);
552
+ if (date) {
553
+ focusedDate = date.clone();
554
+ }
555
+
556
+ if (this.isBlocked(focusedDate)) {
557
+ const days = [];
558
+ const lastVisibleDay = newMonth.clone().add(numberOfMonths - 1, 'months').endOf('month');
559
+ let currentDay = focusedDate.clone();
560
+ while (!isAfterDay(currentDay, lastVisibleDay)) {
561
+ currentDay = currentDay.clone().add(1, 'day');
562
+ days.push(currentDay);
563
+ }
564
+
565
+ const viableDays = days.filter((day) => !this.isBlocked(day) && isAfterDay(day, focusedDate));
566
+ if (viableDays.length > 0) {
567
+ ([focusedDate] = viableDays);
568
+ }
569
+ }
570
+
571
+ return focusedDate;
572
+ }
573
+
574
+ getModifiers(visibleDays) {
575
+ const modifiers = {};
576
+ Object.keys(visibleDays).forEach((month) => {
577
+ modifiers[month] = {};
578
+ visibleDays[month].forEach((day) => {
579
+ modifiers[month][toISODateString(day)] = this.getModifiersForDay(day);
580
+ });
581
+ });
582
+
583
+ return modifiers;
584
+ }
585
+
586
+ getModifiersForDay(day) {
587
+ return new Set(Object.keys(this.modifiers).filter((modifier) => this.modifiers[modifier](day)));
588
+ }
589
+
590
+ getStateForNewMonth(nextProps) {
591
+ const {
592
+ initialVisibleMonth,
593
+ date,
594
+ numberOfMonths,
595
+ orientation,
596
+ enableOutsideDays,
597
+ } = nextProps;
598
+ const initialVisibleMonthThunk = initialVisibleMonth || (date ? () => date : () => this.today);
599
+ const currentMonth = initialVisibleMonthThunk();
600
+ const withoutTransitionMonths = orientation === VERTICAL_SCROLLABLE;
601
+ const visibleDays = this.getModifiers(getVisibleDays(
602
+ currentMonth,
603
+ numberOfMonths,
604
+ enableOutsideDays,
605
+ withoutTransitionMonths,
606
+ ));
607
+ return { currentMonth, visibleDays };
608
+ }
609
+
610
+ shouldDisableMonthNavigation(date, visibleMonth) {
611
+ if (!date) return false;
612
+
613
+ const {
614
+ numberOfMonths,
615
+ enableOutsideDays,
616
+ } = this.props;
617
+
618
+ return isDayVisible(date, visibleMonth, numberOfMonths, enableOutsideDays);
619
+ }
620
+
621
+ addModifier(updatedDays, day, modifier) {
622
+ return addModifier(updatedDays, day, modifier, this.props, this.state);
623
+ }
624
+
625
+ deleteModifier(updatedDays, day, modifier) {
626
+ return deleteModifier(updatedDays, day, modifier, this.props, this.state);
627
+ }
628
+
629
+ isBlocked(day) {
630
+ const { isDayBlocked, isOutsideRange } = this.props;
631
+ return isDayBlocked(day) || isOutsideRange(day);
632
+ }
633
+
634
+ isHovered(day) {
635
+ const { hoverDate } = this.state || {};
636
+ return isSameDay(day, hoverDate);
637
+ }
638
+
639
+ isSelected(day) {
640
+ const { date } = this.props;
641
+ return isSameDay(day, date);
642
+ }
643
+
644
+ isToday(day) {
645
+ return isSameDay(day, this.today);
646
+ }
647
+
648
+ isFirstDayOfWeek(day) {
649
+ return day.day() === this.getFirstDayOfWeek();
650
+ }
651
+
652
+ isLastDayOfWeek(day) {
653
+ return day.day() === (this.getFirstDayOfWeek() + 6) % 7;
654
+ }
655
+
656
+ render() {
657
+ const {
658
+ numberOfMonths,
659
+ orientation,
660
+ monthFormat,
661
+ renderMonthText,
662
+ renderWeekHeaderElement,
663
+ dayPickerNavigationInlineStyles,
664
+ navPosition,
665
+ navPrev,
666
+ navNext,
667
+ renderNavPrevButton,
668
+ renderNavNextButton,
669
+ noNavButtons,
670
+ noNavPrevButton,
671
+ noNavNextButton,
672
+ onOutsideClick,
673
+ onShiftTab,
674
+ onTab,
675
+ withPortal,
676
+ focused,
677
+ enableOutsideDays,
678
+ hideKeyboardShortcutsPanel,
679
+ daySize,
680
+ firstDayOfWeek,
681
+ renderCalendarDay,
682
+ renderDayContents,
683
+ renderCalendarInfo,
684
+ renderMonthElement,
685
+ calendarInfoPosition,
686
+ isFocused,
687
+ isRTL,
688
+ phrases,
689
+ dayAriaLabelFormat,
690
+ onBlur,
691
+ showKeyboardShortcuts,
692
+ weekDayFormat,
693
+ verticalHeight,
694
+ noBorder,
695
+ transitionDuration,
696
+ verticalBorderSpacing,
697
+ horizontalMonthPadding,
698
+ } = this.props;
699
+
700
+ const {
701
+ currentMonth,
702
+ disableNext,
703
+ disablePrev,
704
+ visibleDays,
705
+ } = this.state;
706
+
707
+ return (
708
+ <DayPicker
709
+ orientation={orientation}
710
+ enableOutsideDays={enableOutsideDays}
711
+ modifiers={visibleDays}
712
+ numberOfMonths={numberOfMonths}
713
+ onDayClick={this.onDayClick}
714
+ onDayMouseEnter={this.onDayMouseEnter}
715
+ onDayMouseLeave={this.onDayMouseLeave}
716
+ onPrevMonthClick={this.onPrevMonthClick}
717
+ onNextMonthClick={this.onNextMonthClick}
718
+ onMonthChange={this.onMonthChange}
719
+ onYearChange={this.onYearChange}
720
+ onGetNextScrollableMonths={this.onGetNextScrollableMonths}
721
+ onGetPrevScrollableMonths={this.onGetPrevScrollableMonths}
722
+ monthFormat={monthFormat}
723
+ withPortal={withPortal}
724
+ hidden={!focused}
725
+ hideKeyboardShortcutsPanel={hideKeyboardShortcutsPanel}
726
+ initialVisibleMonth={() => currentMonth}
727
+ firstDayOfWeek={firstDayOfWeek}
728
+ onOutsideClick={onOutsideClick}
729
+ dayPickerNavigationInlineStyles={dayPickerNavigationInlineStyles}
730
+ navPosition={navPosition}
731
+ disablePrev={disablePrev}
732
+ disableNext={disableNext}
733
+ navPrev={navPrev}
734
+ navNext={navNext}
735
+ renderNavPrevButton={renderNavPrevButton}
736
+ renderNavNextButton={renderNavNextButton}
737
+ noNavButtons={noNavButtons}
738
+ noNavNextButton={noNavNextButton}
739
+ noNavPrevButton={noNavPrevButton}
740
+ renderMonthText={renderMonthText}
741
+ renderWeekHeaderElement={renderWeekHeaderElement}
742
+ renderCalendarDay={renderCalendarDay}
743
+ renderDayContents={renderDayContents}
744
+ renderCalendarInfo={renderCalendarInfo}
745
+ renderMonthElement={renderMonthElement}
746
+ calendarInfoPosition={calendarInfoPosition}
747
+ isFocused={isFocused}
748
+ getFirstFocusableDay={this.getFirstFocusableDay}
749
+ onBlur={onBlur}
750
+ onTab={onTab}
751
+ onShiftTab={onShiftTab}
752
+ phrases={phrases}
753
+ daySize={daySize}
754
+ isRTL={isRTL}
755
+ showKeyboardShortcuts={showKeyboardShortcuts}
756
+ weekDayFormat={weekDayFormat}
757
+ dayAriaLabelFormat={dayAriaLabelFormat}
758
+ verticalHeight={verticalHeight}
759
+ noBorder={noBorder}
760
+ transitionDuration={transitionDuration}
761
+ verticalBorderSpacing={verticalBorderSpacing}
762
+ horizontalMonthPadding={horizontalMonthPadding}
763
+ />
764
+ );
765
+ }
766
+ }
767
+
768
+ DayPickerSingleDateController.propTypes = propTypes;
769
+ DayPickerSingleDateController.defaultProps = defaultProps;