@coreui/react-pro 4.2.0-beta.0 → 4.2.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 (163) hide show
  1. package/README.md +1 -1
  2. package/dist/components/accordion/index.d.ts +7 -0
  3. package/dist/components/alert/index.d.ts +4 -0
  4. package/dist/components/avatar/index.d.ts +2 -0
  5. package/dist/components/backdrop/index.d.ts +2 -0
  6. package/dist/components/badge/index.d.ts +2 -0
  7. package/dist/components/breadcrumb/index.d.ts +3 -0
  8. package/dist/components/button/index.d.ts +2 -0
  9. package/dist/components/button-group/index.d.ts +3 -0
  10. package/dist/components/calendar/CCalendar.d.ts +36 -12
  11. package/dist/components/callout/index.d.ts +2 -0
  12. package/dist/components/card/index.d.ts +12 -0
  13. package/dist/components/carousel/index.d.ts +4 -0
  14. package/dist/components/close-button/index.d.ts +2 -0
  15. package/dist/components/collapse/index.d.ts +2 -0
  16. package/dist/components/date-picker/CDatePicker.d.ts +13 -0
  17. package/dist/components/date-picker/index.d.ts +2 -0
  18. package/dist/components/date-range-picker/CDateRangePicker.d.ts +93 -0
  19. package/dist/components/date-range-picker/index.d.ts +2 -0
  20. package/dist/components/datepicker/index.d.ts +2 -0
  21. package/dist/components/daterangepicker/CDateRangePicker.d.ts +26 -11
  22. package/dist/components/daterangepicker/index.d.ts +2 -0
  23. package/dist/components/dropdown/index.d.ts +8 -0
  24. package/dist/components/footer/index.d.ts +2 -0
  25. package/dist/components/form/CForm.d.ts +2 -2
  26. package/dist/components/form/CFormCheck.d.ts +2 -1
  27. package/dist/components/form/CFormControlValidation.d.ts +46 -0
  28. package/dist/components/form/CFormControlWrapper.d.ts +31 -0
  29. package/dist/components/form/CFormInput.d.ts +6 -9
  30. package/dist/components/form/CFormRange.d.ts +7 -1
  31. package/dist/components/form/CFormSelect.d.ts +3 -10
  32. package/dist/components/form/CFormTextarea.d.ts +2 -9
  33. package/dist/components/form/index.d.ts +14 -0
  34. package/dist/components/grid/index.d.ts +4 -0
  35. package/dist/components/header/index.d.ts +7 -0
  36. package/dist/components/image/index.d.ts +2 -0
  37. package/dist/components/index.d.ts +41 -0
  38. package/dist/components/link/index.d.ts +2 -0
  39. package/dist/components/list-group/index.d.ts +3 -0
  40. package/dist/components/loading-button/index.d.ts +2 -0
  41. package/dist/components/modal/CModal.d.ts +3 -0
  42. package/dist/components/modal/index.d.ts +8 -0
  43. package/dist/components/multi-select/index.d.ts +2 -0
  44. package/dist/components/nav/index.d.ts +7 -0
  45. package/dist/components/navbar/index.d.ts +6 -0
  46. package/dist/components/offcanvas/index.d.ts +5 -0
  47. package/dist/components/pagination/index.d.ts +4 -0
  48. package/dist/components/picker/CPicker.d.ts +52 -7
  49. package/dist/components/placeholder/index.d.ts +2 -0
  50. package/dist/components/popover/CPopover.d.ts +2 -2
  51. package/dist/components/popover/index.d.ts +2 -0
  52. package/dist/components/progress/index.d.ts +3 -0
  53. package/dist/components/sidebar/index.d.ts +7 -0
  54. package/dist/components/smart-table/index.d.ts +2 -0
  55. package/dist/components/spinner/index.d.ts +2 -0
  56. package/dist/components/table/index.d.ts +9 -0
  57. package/dist/components/tabs/index.d.ts +3 -0
  58. package/dist/components/time-picker/CTimePicker.d.ts +45 -0
  59. package/dist/components/time-picker/CTimePickerRollCol.d.ts +11 -0
  60. package/dist/components/time-picker/index.d.ts +2 -0
  61. package/dist/components/timepicker/CTimePicker.d.ts +9 -13
  62. package/dist/components/timepicker/index.d.ts +2 -0
  63. package/dist/components/toast/index.d.ts +6 -0
  64. package/dist/components/tooltip/CTooltip.d.ts +6 -2
  65. package/dist/components/tooltip/index.d.ts +2 -0
  66. package/dist/index.d.ts +0 -128
  67. package/dist/index.es.js +8368 -5764
  68. package/dist/index.es.js.map +1 -1
  69. package/dist/index.js +8367 -5764
  70. package/dist/index.js.map +1 -1
  71. package/dist/{components/calendar/CCalendar.utils.d.ts → utils/calendar.d.ts} +5 -2
  72. package/dist/utils/hooks/useStateWithCallback.d.ts +2 -1
  73. package/dist/utils/time.d.ts +21 -0
  74. package/package.json +14 -11
  75. package/src/components/accordion/__tests__/__snapshots__/CAccordionButton.spec.tsx.snap +2 -0
  76. package/src/components/accordion/__tests__/__snapshots__/CAccordionHeader.spec.tsx.snap +2 -0
  77. package/src/components/accordion/index.ts +15 -0
  78. package/src/components/alert/CAlert.tsx +14 -3
  79. package/src/components/alert/index.ts +5 -0
  80. package/src/components/avatar/index.ts +3 -0
  81. package/src/components/backdrop/CBackdrop.tsx +10 -3
  82. package/src/components/backdrop/index.ts +3 -0
  83. package/src/components/badge/index.ts +3 -0
  84. package/src/components/breadcrumb/index.ts +4 -0
  85. package/src/components/button/index.ts +3 -0
  86. package/src/components/button-group/index.ts +4 -0
  87. package/src/components/calendar/CCalendar.tsx +221 -131
  88. package/src/components/calendar/__tests__/CCalendar.spec.tsx +9 -0
  89. package/src/components/calendar/__tests__/__snapshots__/CCalendar.spec.tsx.snap +573 -0
  90. package/src/components/callout/index.ts +3 -0
  91. package/src/components/card/index.ts +25 -0
  92. package/src/components/carousel/index.ts +5 -0
  93. package/src/components/close-button/index.ts +3 -0
  94. package/src/components/collapse/CCollapse.tsx +1 -0
  95. package/src/components/collapse/index.ts +3 -0
  96. package/src/components/{datepicker → date-picker}/CDatePicker.tsx +3 -2
  97. package/src/components/date-picker/__tests__/CDatePicker.spec.tsx +9 -0
  98. package/src/components/date-picker/__tests__/__snapshots__/CDatePicker.spec.tsx.snap +617 -0
  99. package/src/components/date-picker/index.ts +3 -0
  100. package/src/components/date-range-picker/CDateRangePicker.tsx +495 -0
  101. package/src/components/date-range-picker/__tests__/CDateRangePicker.spec.tsx +9 -0
  102. package/src/components/date-range-picker/__tests__/__snapshots__/CDateRangePicker.spec.tsx.snap +1201 -0
  103. package/src/components/date-range-picker/index.ts +3 -0
  104. package/src/components/dropdown/CDropdownItem.tsx +1 -1
  105. package/src/components/dropdown/CDropdownMenu.tsx +14 -14
  106. package/src/components/dropdown/index.ts +17 -0
  107. package/src/components/footer/index.ts +3 -0
  108. package/src/components/form/CForm.tsx +2 -2
  109. package/src/components/form/CFormCheck.tsx +32 -7
  110. package/src/components/form/CFormControlValidation.tsx +97 -0
  111. package/src/components/form/CFormControlWrapper.tsx +85 -0
  112. package/src/components/form/CFormInput.tsx +75 -19
  113. package/src/components/form/CFormRange.tsx +18 -4
  114. package/src/components/form/CFormSelect.tsx +60 -32
  115. package/src/components/form/CFormTextarea.tsx +45 -17
  116. package/src/components/form/index.ts +29 -0
  117. package/src/components/grid/index.ts +5 -0
  118. package/src/components/header/index.ts +8 -0
  119. package/src/components/image/index.ts +3 -0
  120. package/src/components/index.ts +41 -0
  121. package/src/components/link/index.ts +3 -0
  122. package/src/components/list-group/index.ts +4 -0
  123. package/src/components/loading-button/index.ts +3 -0
  124. package/src/components/modal/CModal.tsx +3 -2
  125. package/src/components/modal/index.ts +9 -0
  126. package/src/components/multi-select/CMultiSelect.tsx +46 -38
  127. package/src/components/multi-select/index.ts +3 -0
  128. package/src/components/nav/CNavGroup.tsx +1 -0
  129. package/src/components/nav/index.ts +8 -0
  130. package/src/components/navbar/index.ts +7 -0
  131. package/src/components/offcanvas/COffcanvas.tsx +1 -0
  132. package/src/components/offcanvas/index.ts +6 -0
  133. package/src/components/pagination/index.ts +5 -0
  134. package/src/components/picker/CPicker.tsx +104 -32
  135. package/src/components/picker/__tests__/CPicker.spec.tsx +9 -0
  136. package/src/components/picker/__tests__/__snapshots__/CPicker.spec.tsx.snap +23 -0
  137. package/src/components/placeholder/index.ts +3 -0
  138. package/src/components/popover/CPopover.tsx +59 -57
  139. package/src/components/popover/index.ts +3 -0
  140. package/src/components/progress/index.ts +4 -0
  141. package/src/components/sidebar/index.ts +8 -0
  142. package/src/components/smart-table/CSmartTable.tsx +2 -2
  143. package/src/components/smart-table/index.ts +3 -0
  144. package/src/components/spinner/index.ts +3 -0
  145. package/src/components/table/index.ts +19 -0
  146. package/src/components/tabs/CTabPane.tsx +7 -3
  147. package/src/components/tabs/index.ts +4 -0
  148. package/src/components/{timepicker → time-picker}/CTimePicker.tsx +71 -98
  149. package/src/components/{timepicker → time-picker}/CTimePickerRollCol.tsx +7 -1
  150. package/src/components/time-picker/__tests__/CTimePicker.spec.tsx +9 -0
  151. package/src/components/time-picker/index.ts +3 -0
  152. package/src/components/toast/CToast.tsx +6 -1
  153. package/src/components/toast/index.ts +7 -0
  154. package/src/components/tooltip/CTooltip.tsx +63 -45
  155. package/src/components/tooltip/index.ts +3 -0
  156. package/src/index.ts +0 -258
  157. package/src/{components/calendar/CCalendar.utils.ts → utils/calendar.ts} +97 -10
  158. package/src/utils/hooks/useStateWithCallback.ts +6 -3
  159. package/src/utils/time.ts +84 -0
  160. package/dist/components/dropdown/CDropdownToggleCustom.d.ts +0 -15
  161. package/dist/components/timepicker/CTimePicker.utils.d.ts +0 -4
  162. package/src/components/daterangepicker/CDateRangePicker.tsx +0 -366
  163. package/src/components/timepicker/CTimePicker.utils.ts +0 -27
@@ -3,26 +3,33 @@ import PropTypes from 'prop-types'
3
3
  import classNames from 'classnames'
4
4
 
5
5
  import { CButton } from '../button/CButton'
6
+
6
7
  import {
7
8
  createGroupsInArray,
8
9
  getMonthDetails,
9
10
  getMonthsNames,
10
11
  getYears,
11
- isDisabled,
12
+ isDateDisabled,
12
13
  isDateInRange,
13
14
  isDateSelected,
15
+ isDisableDateInRange,
14
16
  isLastDayOfMonth,
15
17
  isSameDateAs,
16
18
  isToday,
17
19
  isStartDate,
18
20
  isEndDate,
19
- } from './CCalendar.utils'
21
+ } from '../../utils/calendar'
22
+ import { useStateWithCallback } from '../../utils/hooks'
20
23
 
21
24
  export interface CCalendarProps {
22
25
  /**
23
26
  * Default date of the component
24
27
  */
25
28
  calendarDate?: Date | string
29
+ /**
30
+ * The number of calendars that render on desktop devices.
31
+ */
32
+ calendars?: number
26
33
  /**
27
34
  * A string of all className you want applied to the component.
28
35
  */
@@ -37,21 +44,31 @@ export interface CCalendarProps {
37
44
  endDate?: Date | string | null
38
45
  /**
39
46
  * Sets the day of start week.
40
- * 0 - Sunday, 1 - Monday, 2 - Tuesday, 3 - Wednesday, 4 - Thursday, 5 - Friday, 6 - Saturday, 7 - Sunday
47
+ * - 0 - Sunday,
48
+ * - 1 - Monday,
49
+ * - 2 - Tuesday,
50
+ * - 3 - Wednesday,
51
+ * - 4 - Thursday,
52
+ * - 5 - Friday,
53
+ * - 6 - Saturday,
54
+ *
55
+ * @default 1
41
56
  */
42
57
  firstDayOfWeek?: number
43
58
  /**
44
- * Sets the default locale for components. If not set, it is inherited from the navigator.language.
59
+ * Sets the default locale for components. If not set, it is inherited from the browser.
60
+ *
61
+ * @default 'default'
45
62
  */
46
63
  locale?: string
47
64
  /**
48
65
  * Max selectable date.
49
66
  */
50
- maxDate?: Date
67
+ maxDate?: Date | string | null
51
68
  /**
52
69
  * Min selectable date.
53
70
  */
54
- minDate?: Date
71
+ minDate?: Date | string | null
55
72
  /**
56
73
  * Show arrows navigation.
57
74
  */
@@ -59,19 +76,19 @@ export interface CCalendarProps {
59
76
  /**
60
77
  * The custom next icon.
61
78
  */
62
- nextIcon?: ReactNode
79
+ navNextIcon?: ReactNode
63
80
  /**
64
81
  * The custom next double icon.
65
82
  */
66
- nextDoubleIcon?: ReactNode
83
+ navNextDoubleIcon?: ReactNode
67
84
  /**
68
85
  * The custom prev icon.
69
86
  */
70
- prevIcon?: ReactNode
87
+ navPrevIcon?: ReactNode
71
88
  /**
72
89
  * The custom prev double icon.
73
90
  */
74
- prevDoubleIcon?: ReactNode
91
+ navPrevDoubleIcon?: ReactNode
75
92
  /**
76
93
  * Allow range selection.
77
94
  */
@@ -85,9 +102,11 @@ export interface CCalendarProps {
85
102
  */
86
103
  startDate?: Date | string | null
87
104
  /**
88
- * Set length of day name.
105
+ * Set length or format of day name.
106
+ *
107
+ * @default 2
89
108
  */
90
- weekdayLength?: number
109
+ weekdayFormat?: number | 'long' | 'narrow' | 'short'
91
110
  /**
92
111
  * Callback fired when the user hovers over the calendar cell.
93
112
  */
@@ -99,47 +118,54 @@ export interface CCalendarProps {
99
118
  /**
100
119
  * Callback fired when the start date changed.
101
120
  */
102
- onStartDateChange?: (date: Date | null) => void
121
+ onStartDateChange?: (date: Date | null, formatedDate?: string | undefined) => void
103
122
  /**
104
123
  * Callback fired when the end date changed.
105
124
  */
106
- onEndDateChange?: (date: Date | null) => void
125
+ onEndDateChange?: (date: Date | null, formatedDate?: string | undefined) => void
126
+ /**
127
+ * Callback fired when the selection type changed.
128
+ */
129
+ onSelectEndChange?: (value: boolean) => void
130
+ /**
131
+ * Callback fired when the view type of calendar changed.
132
+ */
133
+ onViewChanged?: (view: string) => void
107
134
  }
108
135
 
109
136
  export const CCalendar = forwardRef<HTMLDivElement, CCalendarProps>(
110
137
  (
111
138
  {
112
139
  calendarDate,
140
+ calendars = 1,
141
+ className,
113
142
  disabledDates,
114
143
  endDate,
115
144
  firstDayOfWeek = 1,
116
- locale = typeof navigator === 'undefined' ? 'en-US' : navigator.language,
145
+ locale = 'default',
117
146
  maxDate,
118
147
  minDate,
119
148
  navigation = true,
120
- nextIcon,
121
- nextDoubleIcon,
122
- prevIcon,
123
- prevDoubleIcon,
149
+ navNextIcon,
150
+ navNextDoubleIcon,
151
+ navPrevIcon,
152
+ navPrevDoubleIcon,
124
153
  range,
125
154
  selectEndDate,
126
155
  startDate,
127
- weekdayLength = 2,
156
+ weekdayFormat = 2,
157
+ onCalendarCellHover,
128
158
  onCalendarDateChange,
129
- onStartDateChange,
130
159
  onEndDateChange,
131
- onCalendarCellHover,
160
+ onStartDateChange,
161
+ onSelectEndChange,
162
+ onViewChanged,
132
163
  },
133
164
  ref,
134
165
  ) => {
135
166
  const [_calendarDate, setCalendarDate] = useState<Date>(
136
- calendarDate ? new Date(calendarDate) : new Date(),
167
+ calendarDate ? new Date(calendarDate) : startDate ? new Date(startDate) : new Date(),
137
168
  )
138
- const [_startDate, setStartDate] = useState<Date | null>(startDate ? new Date(startDate) : null)
139
- const [_endDate, setEndDate] = useState<Date | null>(endDate ? new Date(endDate) : null)
140
- const [_selectEndDate, setSelectEndDate] = useState(selectEndDate)
141
- const [view, setView] = useState('days')
142
-
143
169
  useEffect(() => {
144
170
  if (calendarDate) {
145
171
  const d = new Date(calendarDate)
@@ -147,51 +173,49 @@ export const CCalendar = forwardRef<HTMLDivElement, CCalendarProps>(
147
173
  }
148
174
  }, [calendarDate])
149
175
 
176
+ const [_startDate, setStartDate] = useStateWithCallback<Date | null>(
177
+ startDate ? new Date(startDate) : null,
178
+ onStartDateChange,
179
+ )
150
180
  useEffect(() => {
151
- if (startDate === null) {
152
- setStartDate(null)
153
- return
154
- }
155
- if (startDate) {
156
- const d = new Date(startDate)
157
- if (_startDate === null) {
158
- setStartDate(d)
159
- return
160
- }
161
- if (_startDate && !isSameDateAs(d, _startDate)) {
162
- setStartDate(d)
163
- }
181
+ const date = startDate ? new Date(startDate) : null
182
+ if (!isSameDateAs(date, _startDate)) {
183
+ setStartDate(date)
164
184
  }
165
185
  }, [startDate])
166
186
 
187
+ const [_endDate, setEndDate] = useStateWithCallback<Date | null>(
188
+ endDate ? new Date(endDate) : null,
189
+ onEndDateChange,
190
+ )
167
191
  useEffect(() => {
168
- if (endDate === null) {
169
- setEndDate(null)
170
- return
171
- }
172
- if (endDate) {
173
- const d = new Date(endDate)
174
- if (_endDate === null) {
175
- setEndDate(d)
176
- return
177
- }
178
- if (_endDate && !isSameDateAs(d, _endDate)) {
179
- setEndDate(d)
180
- }
192
+ const date = endDate ? new Date(endDate) : null
193
+ if (!isSameDateAs(date, _endDate)) {
194
+ setEndDate(date)
181
195
  }
182
196
  }, [endDate])
183
197
 
198
+ const [_hoverDate, setHoverDate] = useState<Date | null>(null)
199
+
200
+ const [_selectEndDate, setSelectEndDate] = useStateWithCallback(
201
+ selectEndDate,
202
+ onSelectEndChange,
203
+ )
184
204
  useEffect(() => {
185
- _startDate && onStartDateChange && onStartDateChange(_startDate)
186
- }, [_startDate])
205
+ setSelectEndDate(selectEndDate)
206
+ }, [selectEndDate])
187
207
 
208
+ const [_maxDate, setMaxDate] = useState<Date | null>(maxDate ? new Date(maxDate) : null)
188
209
  useEffect(() => {
189
- _endDate && onEndDateChange && onEndDateChange(_endDate)
190
- }, [_endDate])
210
+ maxDate && setMaxDate(new Date(maxDate))
211
+ }, [maxDate])
191
212
 
213
+ const [_minDate, setMinDate] = useState<Date | null>(minDate ? new Date(minDate) : null)
192
214
  useEffect(() => {
193
- setSelectEndDate(selectEndDate)
194
- }, [selectEndDate])
215
+ minDate && setMinDate(new Date(minDate))
216
+ }, [minDate])
217
+
218
+ const [view, setView] = useStateWithCallback('days', onViewChanged)
195
219
 
196
220
  const setCalendarPage = (years: number, months = 0, setMonth?: number) => {
197
221
  const year = _calendarDate.getFullYear()
@@ -200,81 +224,112 @@ export const CCalendar = forwardRef<HTMLDivElement, CCalendarProps>(
200
224
 
201
225
  years && d.setFullYear(d.getFullYear() + years)
202
226
  months && d.setMonth(d.getMonth() + months)
203
- setMonth && d.setMonth(setMonth)
227
+ typeof setMonth === 'number' && d.setMonth(setMonth)
204
228
 
205
229
  setCalendarDate(d)
206
230
  onCalendarDateChange && onCalendarDateChange(d)
207
231
  }
208
232
 
209
233
  const handleCellOnClick = (date: Date) => {
210
- if (isDisabled(date, minDate, maxDate, disabledDates)) {
234
+ if (isDateDisabled(date, _minDate, _maxDate, disabledDates)) {
211
235
  return
212
236
  }
213
237
 
214
238
  if (range) {
215
239
  if (_selectEndDate) {
240
+ setSelectEndDate(false)
241
+
216
242
  if (_startDate && _startDate > date) {
217
- setEndDate(_startDate)
218
- setStartDate(date)
219
- } else {
220
- setEndDate(date)
243
+ setStartDate(null)
244
+ setEndDate(null)
245
+ return
221
246
  }
222
- setSelectEndDate(false)
223
- } else {
224
- setStartDate(date)
225
- setSelectEndDate(true)
247
+
248
+ if (isDisableDateInRange(_startDate, date, disabledDates)) {
249
+ setStartDate(null)
250
+ setEndDate(null)
251
+ return
252
+ }
253
+
254
+ setEndDate(date)
255
+ return
256
+ }
257
+
258
+ if (_endDate && _endDate < date) {
259
+ setStartDate(null)
260
+ setEndDate(null)
261
+ return
262
+ }
263
+
264
+ if (isDisableDateInRange(date, _endDate, disabledDates)) {
265
+ setStartDate(null)
266
+ setEndDate(null)
267
+ return
226
268
  }
227
- } else {
269
+
270
+ setSelectEndDate(true)
228
271
  setStartDate(date)
272
+ return
229
273
  }
274
+
275
+ setStartDate(date)
230
276
  }
231
277
 
232
278
  const handleCellMouseEnter = (date: Date) => {
233
- if (isDisabled(date, minDate, maxDate, disabledDates)) {
279
+ if (isDateDisabled(date, _minDate, _maxDate, disabledDates)) {
234
280
  return
235
281
  }
282
+ setHoverDate(date)
236
283
  onCalendarCellHover && onCalendarCellHover(date)
237
284
  }
238
285
 
239
286
  const handleCellMouseLeave = () => {
287
+ setHoverDate(null)
240
288
  onCalendarCellHover && onCalendarCellHover(null)
241
289
  }
242
290
 
243
291
  const handleNavigationOnClick = (direction: string, double = false) => {
244
292
  if (direction === 'prev') {
245
293
  if (double) {
246
- setCalendarPage(view !== 'days' ? -10 : -1)
294
+ setCalendarPage(view === 'years' ? -10 : -1)
247
295
  return
248
296
  }
297
+
249
298
  if (view !== 'days') {
250
299
  setCalendarPage(-1)
251
300
  return
252
301
  }
302
+
253
303
  setCalendarPage(0, -1)
254
304
  return
255
305
  }
256
306
  if (direction === 'next') {
257
307
  if (double) {
258
- setCalendarPage(view !== 'days' ? 10 : 1)
308
+ setCalendarPage(view === 'years' ? 10 : 1)
259
309
  return
260
310
  }
311
+
261
312
  if (view !== 'days') {
262
313
  setCalendarPage(1)
263
314
  return
264
315
  }
316
+
265
317
  setCalendarPage(0, 1)
266
318
  return
267
319
  }
268
320
  }
269
321
 
270
- const Calendar = () => {
271
- const monthDetails = getMonthDetails(
272
- _calendarDate.getFullYear(),
273
- _calendarDate.getMonth(),
274
- firstDayOfWeek,
275
- )
322
+ const Calendar = (props: { addMonths: number }) => {
323
+ const { addMonths } = props
324
+ let date = _calendarDate
325
+
326
+ if (addMonths !== 0) {
327
+ date = new Date(_calendarDate.getFullYear(), _calendarDate.getMonth() + addMonths, 1)
328
+ }
329
+
330
+ const monthDetails = getMonthDetails(date.getFullYear(), date.getMonth(), firstDayOfWeek)
276
331
  const listOfMonths = createGroupsInArray(getMonthsNames(locale), 4)
277
- const listOfYears = createGroupsInArray(getYears(_calendarDate.getFullYear()), 4)
332
+ const listOfYears = createGroupsInArray(getYears(date.getFullYear()), 4)
278
333
  const weekDays = monthDetails[0]
279
334
  return (
280
335
  <table>
@@ -284,14 +339,18 @@ export const CCalendar = forwardRef<HTMLDivElement, CCalendarProps>(
284
339
  {weekDays.map(({ date }: { date: Date }, idx: number) => (
285
340
  <th key={idx} className="calendar-cell">
286
341
  <div className="calendar-header-cell-inner">
287
- {date.toLocaleDateString(locale, { weekday: 'long' }).slice(0, weekdayLength)}
342
+ {typeof weekdayFormat === 'string'
343
+ ? date.toLocaleDateString(locale, { weekday: weekdayFormat })
344
+ : date
345
+ .toLocaleDateString(locale, { weekday: 'long' })
346
+ .slice(0, weekdayFormat)}
288
347
  </div>
289
348
  </th>
290
349
  ))}
291
350
  </tr>
292
351
  </thead>
293
352
  )}
294
- <tbody onMouseLeave={() => handleCellMouseLeave()}>
353
+ <tbody>
295
354
  {view === 'days' &&
296
355
  monthDetails.map((week, index) => {
297
356
  return (
@@ -299,11 +358,15 @@ export const CCalendar = forwardRef<HTMLDivElement, CCalendarProps>(
299
358
  {week.map(({ date, month }: { date: Date; month: string }, idx: number) => (
300
359
  <td
301
360
  className={classNames('calendar-cell', {
302
- today: isToday(date),
303
- disabled: isDisabled(date, minDate, maxDate, disabledDates),
304
- next: month === 'next',
305
- previous: month === 'previous',
361
+ today: month === 'current' && isToday(date),
362
+ disabled: isDateDisabled(date, _minDate, _maxDate, disabledDates),
363
+ [month]: true,
306
364
  last: isLastDayOfMonth(date),
365
+ 'range-hover':
366
+ month === 'current' &&
367
+ (_hoverDate && _selectEndDate
368
+ ? isDateInRange(date, _startDate, _hoverDate)
369
+ : isDateInRange(date, _hoverDate, _endDate)),
307
370
  range: month === 'current' && isDateInRange(date, _startDate, _endDate),
308
371
  selected: isDateSelected(date, _startDate, _endDate),
309
372
  start: isStartDate(date, _startDate, _endDate),
@@ -311,8 +374,14 @@ export const CCalendar = forwardRef<HTMLDivElement, CCalendarProps>(
311
374
  })}
312
375
  key={idx}
313
376
  title={date.toLocaleDateString(locale)}
314
- onClick={() => handleCellOnClick(date)}
315
- onMouseEnter={() => handleCellMouseEnter(date)}
377
+ {...(month === 'current' && {
378
+ onClick: () => handleCellOnClick(date),
379
+ onMouseEnter: () => handleCellMouseEnter(date),
380
+ onMouseLeave: () => handleCellMouseLeave(),
381
+ })}
382
+ {...(month !== 'current' && {
383
+ onMouseEnter: () => handleCellMouseLeave(),
384
+ })}
316
385
  >
317
386
  <div className="calendar-cell-inner">
318
387
  {date.toLocaleDateString(locale, { day: 'numeric' })}
@@ -332,7 +401,7 @@ export const CCalendar = forwardRef<HTMLDivElement, CCalendarProps>(
332
401
  key={idx}
333
402
  className="calendar-cell month"
334
403
  onClick={() => {
335
- setCalendarPage(0, 0, index * 3 + idx)
404
+ setCalendarPage(0, 0, index * 3 + idx - addMonths)
336
405
  setView('days')
337
406
  }}
338
407
  >
@@ -354,7 +423,7 @@ export const CCalendar = forwardRef<HTMLDivElement, CCalendarProps>(
354
423
  className="calendar-cell year"
355
424
  onClick={() => {
356
425
  setCalendarDate(
357
- new Date(year, _calendarDate.getMonth(), _calendarDate.getDate()),
426
+ new Date(year, date.getMonth() - addMonths, date.getDate()),
358
427
  )
359
428
  setView('months')
360
429
  }}
@@ -373,7 +442,14 @@ export const CCalendar = forwardRef<HTMLDivElement, CCalendarProps>(
373
442
  )
374
443
  }
375
444
 
376
- const Navigation = () => {
445
+ const Navigation = (props: { addMonths: number }) => {
446
+ const { addMonths } = props
447
+ let date = _calendarDate
448
+
449
+ if (addMonths !== 0) {
450
+ date = new Date(_calendarDate.getFullYear(), _calendarDate.getMonth() + addMonths, 1)
451
+ }
452
+
377
453
  return (
378
454
  <div className="calendar-nav">
379
455
  {navigation && (
@@ -383,23 +459,25 @@ export const CCalendar = forwardRef<HTMLDivElement, CCalendarProps>(
383
459
  size="sm"
384
460
  onClick={() => handleNavigationOnClick('prev', true)}
385
461
  >
386
- {prevDoubleIcon ? (
387
- prevDoubleIcon
462
+ {navPrevDoubleIcon ? (
463
+ navPrevDoubleIcon
388
464
  ) : (
389
465
  <span className="calendar-nav-icon calendar-nav-icon-double-prev" />
390
466
  )}
391
467
  </CButton>
392
- <CButton
393
- color="transparent"
394
- size="sm"
395
- onClick={() => handleNavigationOnClick('prev')}
396
- >
397
- {prevIcon ? (
398
- prevIcon
399
- ) : (
400
- <span className="calendar-nav-icon calendar-nav-icon-prev" />
401
- )}
402
- </CButton>
468
+ {view === 'days' && (
469
+ <CButton
470
+ color="transparent"
471
+ size="sm"
472
+ onClick={() => handleNavigationOnClick('prev')}
473
+ >
474
+ {navPrevIcon ? (
475
+ navPrevIcon
476
+ ) : (
477
+ <span className="calendar-nav-icon calendar-nav-icon-prev" />
478
+ )}
479
+ </CButton>
480
+ )}
403
481
  </div>
404
482
  )}
405
483
  <div className="calendar-nav-date">
@@ -409,33 +487,35 @@ export const CCalendar = forwardRef<HTMLDivElement, CCalendarProps>(
409
487
  size="sm"
410
488
  onClick={() => navigation && setView('months')}
411
489
  >
412
- {_calendarDate.toLocaleDateString(locale, { month: 'long' })}
490
+ {date.toLocaleDateString(locale, { month: 'long' })}
413
491
  </CButton>
414
492
  )}
415
493
  <CButton color="transparent" size="sm" onClick={() => navigation && setView('years')}>
416
- {_calendarDate.toLocaleDateString(locale, { year: 'numeric' })}
494
+ {date.toLocaleDateString(locale, { year: 'numeric' })}
417
495
  </CButton>
418
496
  </div>
419
497
  {navigation && (
420
498
  <div className="calendar-nav-next">
421
- <CButton
422
- color="transparent"
423
- size="sm"
424
- onClick={() => handleNavigationOnClick('next')}
425
- >
426
- {nextIcon ? (
427
- nextIcon
428
- ) : (
429
- <span className="calendar-nav-icon calendar-nav-icon-next" />
430
- )}
431
- </CButton>
499
+ {view === 'days' && (
500
+ <CButton
501
+ color="transparent"
502
+ size="sm"
503
+ onClick={() => handleNavigationOnClick('next')}
504
+ >
505
+ {navNextIcon ? (
506
+ navNextIcon
507
+ ) : (
508
+ <span className="calendar-nav-icon calendar-nav-icon-next" />
509
+ )}
510
+ </CButton>
511
+ )}
432
512
  <CButton
433
513
  color="transparent"
434
514
  size="sm"
435
515
  onClick={() => handleNavigationOnClick('next', true)}
436
516
  >
437
- {nextDoubleIcon ? (
438
- nextDoubleIcon
517
+ {navNextDoubleIcon ? (
518
+ navNextDoubleIcon
439
519
  ) : (
440
520
  <span className="calendar-nav-icon calendar-nav-icon-double-next" />
441
521
  )}
@@ -447,9 +527,13 @@ export const CCalendar = forwardRef<HTMLDivElement, CCalendarProps>(
447
527
  }
448
528
 
449
529
  return (
450
- <div className="calendar" ref={ref}>
451
- <Navigation />
452
- <Calendar />
530
+ <div className={classNames('calendars', className)}>
531
+ {Array.from({ length: calendars }, (_, index) => (
532
+ <div className={classNames('calendar', view)} key={index} ref={ref}>
533
+ {Navigation({ addMonths: index })}
534
+ {Calendar({ addMonths: index })}
535
+ </div>
536
+ ))}
453
537
  </div>
454
538
  )
455
539
  },
@@ -458,25 +542,31 @@ export const CCalendar = forwardRef<HTMLDivElement, CCalendarProps>(
458
542
  CCalendar.propTypes = {
459
543
  className: PropTypes.string,
460
544
  calendarDate: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.string]),
545
+ calendars: PropTypes.number,
461
546
  disabledDates: PropTypes.array,
462
547
  endDate: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.string]),
463
548
  firstDayOfWeek: PropTypes.number,
464
549
  locale: PropTypes.string,
465
- maxDate: PropTypes.instanceOf(Date),
466
- minDate: PropTypes.instanceOf(Date),
550
+ maxDate: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.string]),
551
+ minDate: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.string]),
467
552
  navigation: PropTypes.bool,
468
- nextIcon: PropTypes.node,
469
- nextDoubleIcon: PropTypes.node,
470
- prevIcon: PropTypes.node,
471
- prevDoubleIcon: PropTypes.node,
553
+ navNextIcon: PropTypes.node,
554
+ navNextDoubleIcon: PropTypes.node,
555
+ navPrevIcon: PropTypes.node,
556
+ navPrevDoubleIcon: PropTypes.node,
472
557
  range: PropTypes.bool,
473
558
  selectEndDate: PropTypes.bool,
474
559
  startDate: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.string]),
475
- weekdayLength: PropTypes.number,
560
+ weekdayFormat: PropTypes.oneOfType([
561
+ PropTypes.number,
562
+ PropTypes.oneOf<'long' | 'narrow' | 'short'>(['long', 'narrow', 'short']),
563
+ ]),
476
564
  onCalendarCellHover: PropTypes.func,
477
565
  onCalendarDateChange: PropTypes.func,
478
- onStartDateChange: PropTypes.func,
479
566
  onEndDateChange: PropTypes.func,
567
+ onSelectEndChange: PropTypes.func,
568
+ onStartDateChange: PropTypes.func,
569
+ onViewChanged: PropTypes.func,
480
570
  }
481
571
 
482
572
  CCalendar.displayName = 'CCalendar'
@@ -0,0 +1,9 @@
1
+ import * as React from 'react'
2
+ import { render } from '@testing-library/react'
3
+ import '@testing-library/jest-dom/extend-expect'
4
+ import { CCalendar } from '../CCalendar'
5
+
6
+ test('loads and displays CCalendar component', async () => {
7
+ const { container } = render(<CCalendar />)
8
+ expect(container).toMatchSnapshot()
9
+ })