@coreui/vue-pro 5.0.0-alpha.0 → 5.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +1 -1
  2. package/dist/components/calendar/CCalendar.d.ts +58 -32
  3. package/dist/components/calendar/utils.d.ts +11 -4
  4. package/dist/components/close-button/CCloseButton.d.ts +9 -0
  5. package/dist/components/date-picker/CDatePicker.d.ts +89 -0
  6. package/dist/components/date-range-picker/CDateRangePicker.d.ts +89 -0
  7. package/dist/components/dropdown/CDropdown.d.ts +13 -28
  8. package/dist/components/dropdown/CDropdownToggle.d.ts +19 -9
  9. package/dist/components/dropdown/types.d.ts +15 -0
  10. package/dist/components/dropdown/utils.d.ts +6 -0
  11. package/dist/components/form/CFormCheck.d.ts +4 -4
  12. package/dist/components/modal/CModal.d.ts +19 -0
  13. package/dist/components/multi-select/CMultiSelect.d.ts +1 -1
  14. package/dist/components/multi-select/CMultiSelectSelection.d.ts +1 -1
  15. package/dist/components/multi-select/types.d.ts +2 -2
  16. package/dist/components/multi-select/utils.d.ts +2 -2
  17. package/dist/components/offcanvas/COffcanvas.d.ts +9 -0
  18. package/dist/components/progress/CProgress.d.ts +102 -3
  19. package/dist/components/progress/CProgressStacked.d.ts +10 -0
  20. package/dist/components/progress/index.d.ts +2 -1
  21. package/dist/components/smart-table/CSmartTable.d.ts +0 -4
  22. package/dist/components/smart-table/CSmartTableBody.d.ts +12 -1
  23. package/dist/components/smart-table/types.d.ts +2 -2
  24. package/dist/components/smart-table/utils.d.ts +4 -2
  25. package/dist/composables/index.d.ts +2 -1
  26. package/dist/composables/useDebouncedCallback.d.ts +1 -0
  27. package/dist/index.es.js +1035 -2716
  28. package/dist/index.es.js.map +1 -1
  29. package/dist/index.js +1035 -2714
  30. package/dist/index.js.map +1 -1
  31. package/package.json +14 -14
  32. package/src/components/breadcrumb/CBreadcrumb.ts +1 -0
  33. package/src/components/button/CButton.ts +5 -5
  34. package/src/components/calendar/CCalendar.ts +444 -179
  35. package/src/components/calendar/utils.ts +93 -55
  36. package/src/components/carousel/CCarousel.ts +2 -5
  37. package/src/components/close-button/CCloseButton.ts +5 -0
  38. package/src/components/date-picker/CDatePicker.ts +43 -0
  39. package/src/components/date-range-picker/CDateRangePicker.ts +130 -83
  40. package/src/components/date-range-picker/utils.ts +2 -2
  41. package/src/components/dropdown/CDropdown.ts +23 -43
  42. package/src/components/dropdown/CDropdownMenu.ts +4 -19
  43. package/src/components/dropdown/CDropdownToggle.ts +44 -38
  44. package/src/components/dropdown/types.ts +11 -0
  45. package/src/components/dropdown/utils.ts +71 -0
  46. package/src/components/form/CFormCheck.ts +4 -4
  47. package/src/components/modal/CModal.ts +15 -1
  48. package/src/components/multi-select/CMultiSelect.ts +5 -8
  49. package/src/components/multi-select/CMultiSelectOptions.ts +1 -1
  50. package/src/components/multi-select/CMultiSelectSelection.ts +3 -3
  51. package/src/components/multi-select/types.ts +2 -2
  52. package/src/components/multi-select/utils.ts +5 -5
  53. package/src/components/navbar/CNavbar.ts +1 -1
  54. package/src/components/offcanvas/COffcanvas.ts +6 -0
  55. package/src/components/picker/CPicker.ts +1 -1
  56. package/src/components/progress/CProgress.ts +67 -9
  57. package/src/components/progress/CProgressBar.ts +4 -6
  58. package/src/components/progress/CProgressStacked.ts +19 -0
  59. package/src/components/progress/index.ts +3 -1
  60. package/src/components/sidebar/CSidebar.ts +1 -1
  61. package/src/components/smart-pagination/CSmartPagination.ts +20 -5
  62. package/src/components/smart-table/CSmartTable.ts +21 -12
  63. package/src/components/smart-table/CSmartTableBody.ts +30 -31
  64. package/src/components/smart-table/CSmartTableHead.ts +39 -12
  65. package/src/components/smart-table/types.ts +2 -2
  66. package/src/components/smart-table/utils.ts +41 -5
  67. package/src/components/time-picker/CTimePicker.ts +4 -2
  68. package/src/components/tooltip/CTooltip.ts +1 -1
  69. package/src/components/widgets/CWidgetStatsA.ts +1 -3
  70. package/src/components/widgets/CWidgetStatsB.ts +2 -4
  71. package/src/components/widgets/CWidgetStatsC.ts +2 -2
  72. package/src/components/widgets/CWidgetStatsD.ts +1 -1
  73. package/src/components/widgets/CWidgetStatsE.ts +1 -1
  74. package/src/components/widgets/CWidgetStatsF.ts +1 -1
  75. package/src/components/widgets/__tests__/__snapshots__/CWidgetStatsE.spec.ts.snap +1 -1
  76. package/src/composables/index.ts +2 -1
  77. package/src/composables/useDebouncedCallback.ts +16 -0
  78. package/src/utils/isObjectInArray.ts +1 -1
@@ -3,7 +3,10 @@ import { defineComponent, h, PropType, ref, watch } from 'vue'
3
3
  import { CButton } from '../button'
4
4
 
5
5
  import {
6
+ convertToDateObject,
6
7
  createGroupsInArray,
8
+ getCalendarDate,
9
+ getDateBySelectionType,
7
10
  getMonthDetails,
8
11
  getMonthsNames,
9
12
  getYears,
@@ -11,11 +14,8 @@ import {
11
14
  isDateInRange,
12
15
  isDateSelected,
13
16
  isDisableDateInRange,
14
- isLastDayOfMonth,
15
17
  isSameDateAs,
16
18
  isToday,
17
- isStartDate,
18
- isEndDate,
19
19
  } from './utils'
20
20
 
21
21
  const CCalendar = defineComponent({
@@ -24,9 +24,7 @@ const CCalendar = defineComponent({
24
24
  /**
25
25
  * Default date of the component
26
26
  */
27
- calendarDate: {
28
- type: [Date, String],
29
- },
27
+ calendarDate: null as unknown as PropType<Date | string | null>,
30
28
  /**
31
29
  * The number of calendars that render on desktop devices.
32
30
  */
@@ -66,9 +64,7 @@ const CCalendar = defineComponent({
66
64
  /**
67
65
  * Initial selected to date (range).
68
66
  */
69
- endDate: {
70
- type: [Date, String],
71
- },
67
+ endDate: null as unknown as PropType<Date | string | null>,
72
68
  /**
73
69
  * Sets the day of start week.
74
70
  * - 0 - Sunday,
@@ -93,15 +89,11 @@ const CCalendar = defineComponent({
93
89
  /**
94
90
  * Max selectable date.
95
91
  */
96
- maxDate: {
97
- type: [Date, String],
98
- },
92
+ maxDate: null as unknown as PropType<Date | string | null>,
99
93
  /**
100
94
  * Min selectable date.
101
95
  */
102
- minDate: {
103
- type: [Date, String],
104
- },
96
+ minDate: null as unknown as PropType<Date | string | null>,
105
97
  /**
106
98
  * Show arrows navigation.
107
99
  */
@@ -129,6 +121,16 @@ const CCalendar = defineComponent({
129
121
  * @since 4.9.0
130
122
  */
131
123
  selectAdjacementDays: Boolean,
124
+ /**
125
+ * Specify the type of date selection as day, week, month, or year.
126
+ *
127
+ * @since 5.0.0-alpha.1
128
+ */
129
+ selectionType: {
130
+ type: String as PropType<'day' | 'week' | 'month' | 'year'>,
131
+ default: 'day',
132
+ validator: (value: string) => ['day', 'week', 'month', 'year'].includes(value),
133
+ },
132
134
  /**
133
135
  * Set whether to display dates in adjacent months (non-selectable) at the start and end of the current month.
134
136
  *
@@ -138,12 +140,16 @@ const CCalendar = defineComponent({
138
140
  type: Boolean,
139
141
  default: true,
140
142
  },
143
+ /**
144
+ * Set whether to display week numbers in the calendar.
145
+ *
146
+ * @since 5.0.0-alpha.1
147
+ */
148
+ showWeekNumber: Boolean,
141
149
  /**
142
150
  * Initial selected date.
143
151
  */
144
- startDate: {
145
- type: [Date, String],
146
- },
152
+ startDate: null as unknown as PropType<Date | string | null>,
147
153
  /**
148
154
  * Set length or format of day name.
149
155
  *
@@ -165,6 +171,12 @@ const CCalendar = defineComponent({
165
171
  return false
166
172
  },
167
173
  },
174
+ /**
175
+ * Label displayed over week numbers in the calendar.
176
+ *
177
+ * @since 5.0.0-alpha.1
178
+ */
179
+ weekNumbersLabel: String,
168
180
  },
169
181
  emits: [
170
182
  /**
@@ -172,7 +184,7 @@ const CCalendar = defineComponent({
172
184
  *
173
185
  * @property {Date | null} date
174
186
  */
175
- 'calendar-cell-hover',
187
+ 'date-hover',
176
188
  /**
177
189
  * Callback fired when the calendar date changed.
178
190
  *
@@ -193,20 +205,50 @@ const CCalendar = defineComponent({
193
205
  'end-date-change',
194
206
  ],
195
207
  setup(props, { slots, emit }) {
208
+ const calendarRef = ref<HTMLDivElement>()
196
209
  const calendarDate = ref(
197
210
  props.calendarDate
198
- ? new Date(props.calendarDate)
211
+ ? convertToDateObject(props.calendarDate, props.selectionType)
199
212
  : props.startDate
200
- ? new Date(props.startDate)
213
+ ? convertToDateObject(props.startDate, props.selectionType)
201
214
  : new Date(),
202
215
  )
203
- const startDate = ref(props.startDate ? new Date(props.startDate) : null)
204
- const endDate = ref(props.endDate ? new Date(props.endDate) : null)
216
+ const startDate = ref<Date | null>(
217
+ props.startDate ? convertToDateObject(props.startDate, props.selectionType) : null,
218
+ )
219
+ const endDate = ref(
220
+ props.endDate ? convertToDateObject(props.endDate, props.selectionType) : null,
221
+ )
205
222
  const hoverDate = ref<Date | null>(null)
206
- const maxDate = ref(props.maxDate ? new Date(props.maxDate) : null)
207
- const minDate = ref(props.minDate ? new Date(props.minDate) : null)
223
+ const maxDate = ref(
224
+ props.maxDate ? convertToDateObject(props.maxDate, props.selectionType) : null,
225
+ )
226
+ const minDate = ref(
227
+ props.minDate ? convertToDateObject(props.minDate, props.selectionType) : null,
228
+ )
208
229
  const selectEndDate = ref(props.selectEndDate)
209
- const view = ref('days')
230
+ const view = ref<'days' | 'months' | 'years'>('days')
231
+
232
+ watch(
233
+ () => props.selectionType,
234
+ () => {
235
+ if (props.selectionType === 'day' || props.selectionType === 'week') {
236
+ view.value = 'days'
237
+ return
238
+ }
239
+
240
+ if (props.selectionType === 'month') {
241
+ view.value = 'months'
242
+ return
243
+ }
244
+
245
+ if (props.selectionType === 'year') {
246
+ view.value = 'years'
247
+ return
248
+ }
249
+ },
250
+ { immediate: true },
251
+ )
210
252
 
211
253
  watch(
212
254
  () => props.calendarDate,
@@ -220,7 +262,9 @@ const CCalendar = defineComponent({
220
262
  watch(
221
263
  () => props.startDate,
222
264
  () => {
223
- const date = props.startDate ? new Date(props.startDate) : null
265
+ const date = props.startDate
266
+ ? convertToDateObject(props.startDate, props.selectionType)
267
+ : null
224
268
  if (!isSameDateAs(date, startDate.value)) {
225
269
  startDate.value = date
226
270
  }
@@ -230,7 +274,7 @@ const CCalendar = defineComponent({
230
274
  watch(
231
275
  () => props.endDate,
232
276
  () => {
233
- const date = props.endDate ? new Date(props.endDate) : null
277
+ const date = props.endDate ? convertToDateObject(props.endDate, props.selectionType) : null
234
278
  if (!isSameDateAs(date, endDate.value)) {
235
279
  endDate.value = date
236
280
  }
@@ -241,7 +285,7 @@ const CCalendar = defineComponent({
241
285
  () => props.maxDate,
242
286
  () => {
243
287
  if (props.maxDate) {
244
- maxDate.value = new Date(props.maxDate)
288
+ maxDate.value = convertToDateObject(props.maxDate, props.selectionType)
245
289
  }
246
290
  },
247
291
  )
@@ -250,7 +294,7 @@ const CCalendar = defineComponent({
250
294
  () => props.minDate,
251
295
  () => {
252
296
  if (props.minDate) {
253
- minDate.value = new Date(props.minDate)
297
+ minDate.value = convertToDateObject(props.minDate, props.selectionType)
254
298
  }
255
299
  },
256
300
  )
@@ -263,11 +307,11 @@ const CCalendar = defineComponent({
263
307
  )
264
308
 
265
309
  watch(startDate, () => {
266
- emit('start-date-change', startDate.value)
310
+ emit('start-date-change', getDateBySelectionType(startDate.value, props.selectionType))
267
311
  })
268
312
 
269
313
  watch(endDate, () => {
270
- emit('end-date-change', endDate.value)
314
+ emit('end-date-change', getDateBySelectionType(endDate.value, props.selectionType))
271
315
  })
272
316
 
273
317
  const setCalendarPage = (years: number, months = 0, setMonth?: number) => {
@@ -284,11 +328,31 @@ const CCalendar = defineComponent({
284
328
  emit('calendar-date-change', d)
285
329
  }
286
330
 
287
- const handleCellOnClick = (date: Date) => {
331
+ const handleCalendarClick = (date: Date, index?: number) => {
288
332
  if (isDateDisabled(date, minDate.value, maxDate.value, props.disabledDates)) {
289
333
  return
290
334
  }
291
335
 
336
+ const _date = new Date(date)
337
+
338
+ if (view.value === 'days') {
339
+ calendarDate.value = index ? new Date(_date.setMonth(_date.getMonth() - index)) : _date
340
+ }
341
+
342
+ if (view.value === 'months' && props.selectionType !== 'month') {
343
+ calendarDate.value = index ? new Date(_date.setMonth(_date.getMonth() - index)) : _date
344
+ view.value = 'days'
345
+ return
346
+ }
347
+
348
+ if (view.value === 'years' && props.selectionType !== 'year') {
349
+ calendarDate.value = index
350
+ ? new Date(_date.setFullYear(_date.getFullYear() - index))
351
+ : _date
352
+ view.value = 'months'
353
+ return
354
+ }
355
+
292
356
  if (props.range) {
293
357
  if (selectEndDate.value) {
294
358
  selectEndDate.value = false
@@ -329,97 +393,211 @@ const CCalendar = defineComponent({
329
393
  startDate.value = date
330
394
  }
331
395
 
332
- const handleCellKeyDown = (event: KeyboardEvent, date: Date) => {
396
+ const handleCalendarKeyDown = (event: KeyboardEvent, date: Date, index?: number) => {
333
397
  if (event.code === 'Space' || event.key === 'Enter') {
334
398
  event.preventDefault()
335
- handleCellOnClick && handleCellOnClick(date)
336
- return
399
+ handleCalendarClick(date, index)
400
+ }
401
+
402
+ if (
403
+ event.key === 'ArrowRight' ||
404
+ event.key === 'ArrowLeft' ||
405
+ event.key === 'ArrowUp' ||
406
+ event.key === 'ArrowDown'
407
+ ) {
408
+ event.preventDefault()
409
+
410
+ if (
411
+ maxDate.value &&
412
+ date >= convertToDateObject(maxDate.value, props.selectionType) &&
413
+ (event.key === 'ArrowRight' || event.key === 'ArrowDown')
414
+ ) {
415
+ return
416
+ }
417
+
418
+ if (
419
+ minDate.value &&
420
+ date <= convertToDateObject(minDate.value, props.selectionType) &&
421
+ (event.key === 'ArrowLeft' || event.key === 'ArrowUp')
422
+ ) {
423
+ return
424
+ }
425
+
426
+ let element = event.target as HTMLElement
427
+
428
+ if (props.selectionType === 'week' && element.tabIndex === -1) {
429
+ element = element.closest('tr[tabindex="0"]') as HTMLElement
430
+ }
431
+
432
+ const list: HTMLElement[] = calendarRef.value
433
+ ? Array.from(
434
+ calendarRef.value.querySelectorAll(
435
+ props.selectionType === 'week' ? 'tr[tabindex="0"]' : 'td.current',
436
+ ),
437
+ )
438
+ : []
439
+ // const list: HTMLElement[] = [].concat(
440
+ // ...Element.prototype.querySelectorAll.call(
441
+ // calendarRef.value,
442
+ // props.selectionType === 'week' ? 'tr[tabindex="0"]' : 'td.current',
443
+ // ),
444
+ // )
445
+
446
+ const index = list.indexOf(element)
447
+ const first = index === 0
448
+ const last = index === list.length - 1
449
+
450
+ const toBoundary = {
451
+ start: index,
452
+ end: list.length - (index + 1),
453
+ }
454
+
455
+ const gap = {
456
+ ArrowRight: 1,
457
+ ArrowLeft: -1,
458
+ ArrowUp:
459
+ props.selectionType === 'week' && view.value === 'days'
460
+ ? -1
461
+ : view.value === 'days'
462
+ ? -7
463
+ : -3,
464
+ ArrowDown:
465
+ props.selectionType === 'week' && view.value === 'days'
466
+ ? 1
467
+ : view.value === 'days'
468
+ ? 7
469
+ : 3,
470
+ }
471
+
472
+ if (
473
+ (event.key === 'ArrowRight' && last) ||
474
+ (event.key === 'ArrowDown' && toBoundary['end'] < gap['ArrowDown']) ||
475
+ (event.key === 'ArrowLeft' && first) ||
476
+ (event.key === 'ArrowUp' && toBoundary['start'] < Math.abs(gap['ArrowUp']))
477
+ ) {
478
+ if (view.value === 'days') {
479
+ setCalendarPage(0, event.key === 'ArrowRight' || event.key === 'ArrowDown' ? 1 : -1)
480
+ }
481
+
482
+ if (view.value === 'months') {
483
+ setCalendarPage(event.key === 'ArrowRight' || event.key === 'ArrowDown' ? 1 : -1)
484
+ }
485
+
486
+ if (view.value === 'years') {
487
+ setCalendarPage(event.key === 'ArrowRight' || event.key === 'ArrowDown' ? 10 : -10)
488
+ }
489
+
490
+ setTimeout(() => {
491
+ const _list: HTMLElement[] = element.parentNode?.parentNode ? Array.from(
492
+ element.parentNode.parentNode.querySelectorAll('td[tabindex="0"], tr[tabindex="0"]'),
493
+ ) : []
494
+
495
+ if (_list.length && event.key === 'ArrowRight') {
496
+ _list[0].focus()
497
+ }
498
+
499
+ if (_list.length && event.key === 'ArrowLeft') {
500
+ _list[_list.length - 1].focus()
501
+ }
502
+
503
+ if (_list.length && event.key === 'ArrowDown') {
504
+ _list[gap['ArrowDown'] - (list.length - index)].focus()
505
+ }
506
+
507
+ if (_list.length && event.key === 'ArrowUp') {
508
+ _list[_list.length - (Math.abs(gap['ArrowUp']) + 1 - (index + 1))].focus()
509
+ }
510
+ }, 1)
511
+
512
+ return
513
+ }
514
+
515
+ if (list[index + gap[event.key]].tabIndex === 0) {
516
+ list[index + gap[event.key]].focus()
517
+ return
518
+ }
519
+
520
+ for (
521
+ let i = index;
522
+ i < list.length;
523
+ event.key === 'ArrowRight' || event.key === 'ArrowDown' ? i++ : i--
524
+ ) {
525
+ if (list[i + gap[event.key]].tabIndex === 0) {
526
+ list[i + gap[event.key]].focus()
527
+ break
528
+ }
529
+ }
337
530
  }
338
531
  }
339
532
 
340
- const handleCellMouseEnter = (date: Date) => {
533
+ const handleCalendarMouseEnter = (date: Date) => {
341
534
  if (isDateDisabled(date, minDate.value, maxDate.value, props.disabledDates)) {
342
535
  return
343
536
  }
344
537
 
345
538
  hoverDate.value = date
346
- emit('calendar-cell-hover', date)
539
+ emit('date-hover', getDateBySelectionType(date, props.selectionType))
347
540
  }
348
541
 
349
- const handleCellMouseLeave = () => {
542
+ const handleCalendarMouseLeave = () => {
350
543
  hoverDate.value = null
351
- emit('calendar-cell-hover', null)
352
- }
353
-
354
- const handleMonthKeyDown = (event: KeyboardEvent, month: number) => {
355
- if (event.code === 'Space' || event.key === 'Enter') {
356
- setCalendarPage(0, month)
357
- view.value = 'days'
358
- }
359
- }
360
-
361
- const handleYearKeyDown = (event: KeyboardEvent, date: Date) => {
362
- if (event.code === 'Space' || event.key === 'Enter') {
363
- calendarDate.value = date
364
- view.value = 'months'
365
- }
544
+ emit('date-hover', null)
366
545
  }
367
546
 
368
547
  const handleNavigationOnClick = (direction: string, double = false) => {
369
548
  if (direction === 'prev') {
370
549
  if (double) {
371
- setCalendarPage(view.value === 'days' ? -1 : -10)
550
+ setCalendarPage(view.value === 'years' ? -10 : -1)
372
551
  return
373
552
  }
553
+
374
554
  if (view.value !== 'days') {
375
555
  setCalendarPage(-1)
376
556
  return
377
557
  }
558
+
378
559
  setCalendarPage(0, -1)
379
560
  return
380
561
  }
562
+
381
563
  if (direction === 'next') {
382
564
  if (double) {
383
- setCalendarPage(view.value === 'days' ? 1 : 10)
565
+ setCalendarPage(view.value === 'years' ? 10 : 1)
384
566
  return
385
567
  }
568
+
386
569
  if (view.value !== 'days') {
387
570
  setCalendarPage(1)
388
571
  return
389
572
  }
573
+
390
574
  setCalendarPage(0, 1)
391
575
  return
392
576
  }
393
577
  }
394
578
 
395
- const Calendar = (addMonths: number) => {
396
- let date = calendarDate.value
397
-
398
- if (addMonths !== 0) {
399
- date = new Date(
400
- calendarDate.value.getFullYear(),
401
- calendarDate.value.getMonth() + addMonths,
402
- 1,
403
- )
404
- }
405
-
579
+ const Calendar = (_calendarDate: Date) => {
406
580
  const monthDetails = getMonthDetails(
407
- date.getFullYear(),
408
- date.getMonth(),
581
+ _calendarDate.getFullYear(),
582
+ _calendarDate.getMonth(),
409
583
  props.firstDayOfWeek,
410
584
  )
411
585
  const listOfMonths = createGroupsInArray(getMonthsNames(props.locale), 4)
412
- const listOfYears = createGroupsInArray(getYears(date.getFullYear()), 4)
413
- const weekDays = monthDetails[0]
586
+ const listOfYears = createGroupsInArray(getYears(_calendarDate.getFullYear()), 4)
587
+ const weekDays = monthDetails[0].days
414
588
 
415
589
  return h('table', {}, [
416
590
  view.value === 'days' &&
417
591
  h(
418
592
  'thead',
419
593
  {},
420
- h(
421
- 'tr',
422
- {},
594
+ h('tr', {}, [
595
+ props.showWeekNumber &&
596
+ h(
597
+ 'th',
598
+ { class: 'calendar-cell' },
599
+ h('div', { class: 'calendar-header-cell-inner' }, props.weekNumbersLabel),
600
+ ),
423
601
  weekDays.map(({ date }: { date: Date }) => {
424
602
  return h(
425
603
  'th',
@@ -441,78 +619,122 @@ const CCalendar = defineComponent({
441
619
  ),
442
620
  )
443
621
  }),
444
- ),
622
+ ]),
445
623
  ),
446
624
  h('tbody', {}, [
447
625
  view.value === 'days' &&
448
626
  monthDetails.map((week) => {
627
+ const date = convertToDateObject(
628
+ week.weekNumber === 0
629
+ ? `${_calendarDate.getFullYear()}W53`
630
+ : `${_calendarDate.getFullYear()}W${week.weekNumber}`,
631
+ props.selectionType,
632
+ )
633
+ const isDisabled = isDateDisabled(
634
+ date,
635
+ minDate.value,
636
+ maxDate.value,
637
+ props.disabledDates,
638
+ )
639
+ const current = week.days.some((day) => day.month === 'current')
449
640
  return h(
450
641
  'tr',
451
- {},
452
- week.map(({ date, month }: { date: Date; month: string }) => {
453
- return month === 'current' || props.showAdjacementDays
454
- ? h(
455
- 'td',
456
- {
457
- class: [
458
- 'calendar-cell',
459
- {
460
- today: isToday(date),
461
- disabled: isDateDisabled(
462
- date,
463
- minDate.value,
464
- maxDate.value,
465
- props.disabledDates,
466
- ),
467
- [month]: true,
468
- clickable: month !== 'current' && props.selectAdjacementDays,
469
- last: isLastDayOfMonth(date),
470
- range:
471
- month === 'current' &&
472
- isDateInRange(date, startDate.value, endDate.value),
473
- 'range-hover':
474
- month === 'current' &&
475
- (hoverDate.value && selectEndDate.value
476
- ? isDateInRange(date, startDate.value, hoverDate.value)
477
- : isDateInRange(date, hoverDate.value, endDate.value)),
478
- selected: isDateSelected(date, startDate.value, endDate.value),
479
- start: isStartDate(date, startDate.value, endDate.value),
480
- end: isEndDate(date, startDate.value, endDate.value),
481
- },
482
- ],
483
- tabindex:
484
- (month === 'current' || props.selectAdjacementDays) &&
485
- !isDateDisabled(date, minDate.value, maxDate.value, props.disabledDates)
486
- ? 0
487
- : -1,
488
- title: date.toLocaleDateString(props.locale),
489
- ...((month === 'current' || props.selectAdjacementDays) && {
490
- onBlur: () => handleCellMouseLeave(),
491
- onClick: () => handleCellOnClick(date),
492
- onFocus: () => handleCellMouseEnter(date),
493
- onKeydown: (event: KeyboardEvent) => handleCellKeyDown(event, date),
494
- onmouseenter: () => handleCellMouseEnter(date),
495
- onmouseleave: () => handleCellMouseLeave(),
496
- }),
497
- ...(month !== 'current' &&
498
- !props.selectAdjacementDays && {
499
- onMouseEnter: () => handleCellMouseLeave(),
500
- }),
501
- },
502
- h(
503
- 'div',
642
+ {
643
+ class: [
644
+ 'calendar-row',
645
+ {
646
+ disabled: isDisabled,
647
+ range:
648
+ props.selectionType === 'week' &&
649
+ isDateInRange(date, startDate.value, endDate.value),
650
+ 'range-hover':
651
+ props.selectionType === 'week' && hoverDate.value && selectEndDate.value
652
+ ? isDateInRange(date, startDate.value, hoverDate.value)
653
+ : isDateInRange(date, hoverDate.value, endDate.value),
654
+ selected: isDateSelected(date, startDate.value, endDate.value),
655
+ },
656
+ ],
657
+ tabindex: props.selectionType === 'week' && current && !isDisabled ? 0 : -1,
658
+ ...(props.selectionType === 'week' &&
659
+ !isDisabled && {
660
+ onBlur: () => handleCalendarMouseLeave(),
661
+ onClick: () => handleCalendarClick(date),
662
+ onFocus: () => handleCalendarMouseEnter(date),
663
+ onKeydown: (event: KeyboardEvent) => handleCalendarKeyDown(event, date),
664
+ onMouseEnter: () => handleCalendarMouseEnter(date),
665
+ onMouseLeave: () => handleCalendarMouseLeave(),
666
+ }),
667
+ },
668
+ [
669
+ props.showWeekNumber &&
670
+ h(
671
+ 'th',
672
+ { class: 'calendar-cell-week-number' },
673
+ week.weekNumber === 0 ? 53 : week.weekNumber,
674
+ ),
675
+ week.days.map(({ date, month }: { date: Date; month: string }) => {
676
+ const isDisabled = isDateDisabled(date, minDate.value, maxDate.value, props.disabledDates)
677
+ return month === 'current' || props.showAdjacementDays
678
+ ? h(
679
+ 'td',
504
680
  {
505
- class: 'calendar-cell-inner',
506
- },
507
- typeof props.dayFormat === 'function'
508
- ? props.dayFormat(date)
509
- : date.toLocaleDateString(props.locale, {
510
- day: <'numeric' | '2-digit'>props.dayFormat,
681
+ class: [
682
+ 'calendar-cell',
683
+ {
684
+ ...(props.selectionType === 'day' && {
685
+ clickable: month !== 'current' && props.selectAdjacementDays,
686
+ disabled: isDisabled,
687
+ 'range-hover':
688
+ month === 'current' &&
689
+ (hoverDate.value && selectEndDate.value
690
+ ? isDateInRange(date, startDate.value, hoverDate.value)
691
+ : isDateInRange(date, hoverDate.value, endDate.value)),
692
+ range:
693
+ month === 'current' &&
694
+ isDateInRange(date, startDate.value, endDate.value),
695
+ selected: isDateSelected(date, startDate.value, endDate.value),
696
+ }),
697
+ [month]: true,
698
+ today: month === 'current' && isToday(date),
699
+ },
700
+ ],
701
+ tabindex:
702
+ props.selectionType === 'day' &&
703
+ (month === 'current' || props.selectAdjacementDays) &&
704
+ !isDisabled
705
+ ? 0
706
+ : -1,
707
+ title: date.toLocaleDateString(props.locale),
708
+ ...(props.selectionType === 'day' &&
709
+ (month === 'current' || props.selectAdjacementDays) && {
710
+ onBlur: () => handleCalendarMouseLeave(),
711
+ onClick: () => handleCalendarClick(date),
712
+ onFocus: () => handleCalendarMouseEnter(date),
713
+ onKeydown: (event: KeyboardEvent) =>
714
+ handleCalendarKeyDown(event, date),
715
+ onMouseEnter: () => handleCalendarMouseEnter(date),
716
+ onMouseLeave: () => handleCalendarMouseLeave(),
511
717
  }),
512
- ),
513
- )
514
- : h('td')
515
- }),
718
+ ...(month !== 'current' &&
719
+ !props.selectAdjacementDays && {
720
+ onMouseEnter: () => handleCalendarMouseLeave(),
721
+ }),
722
+ },
723
+ h(
724
+ 'div',
725
+ {
726
+ class: 'calendar-cell-inner',
727
+ },
728
+ typeof props.dayFormat === 'function'
729
+ ? props.dayFormat(date)
730
+ : date.toLocaleDateString(props.locale, {
731
+ day: <'numeric' | '2-digit'>props.dayFormat,
732
+ }),
733
+ ),
734
+ )
735
+ : h('td')
736
+ }),
737
+ ],
516
738
  )
517
739
  }),
518
740
  view.value === 'months' &&
@@ -521,17 +743,39 @@ const CCalendar = defineComponent({
521
743
  'tr',
522
744
  {},
523
745
  row.map((month, idx) => {
746
+ const monthNumber = index * 3 + idx
747
+ const date = new Date(Date.UTC(_calendarDate.getFullYear(), monthNumber, 1))
748
+ const isDisabled = isDateDisabled(
749
+ date,
750
+ minDate.value,
751
+ maxDate.value,
752
+ props.disabledDates,
753
+ )
524
754
  return h(
525
755
  'td',
526
756
  {
527
- class: 'calendar-cell month',
528
- onClick: () => {
529
- setCalendarPage(0, 0, index * 3 + idx - addMonths)
530
- view.value = 'days'
531
- },
532
- onKeydown: (event: KeyboardEvent) =>
533
- handleMonthKeyDown(event, index * 3 + idx - addMonths),
534
- tabindex: 0,
757
+ class: [
758
+ 'calendar-cell',
759
+ {
760
+ disabled: isDisabled,
761
+ selected: isDateSelected(date, startDate.value, endDate.value),
762
+ 'range-hover':
763
+ props.selectionType === 'month' &&
764
+ (hoverDate && selectEndDate
765
+ ? isDateInRange(date, startDate.value, hoverDate.value)
766
+ : isDateInRange(date, hoverDate.value, endDate.value)),
767
+ range: isDateInRange(date, startDate.value, endDate.value),
768
+ },
769
+ ],
770
+ tabindex: !isDisabled ? 0 : -1,
771
+ ...(!isDisabled && {
772
+ onBlur: () => handleCalendarMouseLeave(),
773
+ onClick: () => handleCalendarClick(date),
774
+ onFocus: () => handleCalendarMouseEnter(date),
775
+ onKeydown: (event: KeyboardEvent) => handleCalendarKeyDown(event, date),
776
+ onMouseEnter: () => handleCalendarMouseEnter(date),
777
+ onMouseLeave: () => handleCalendarMouseLeave(),
778
+ }),
535
779
  },
536
780
  h('div', { class: 'calendar-cell-inner' }, month),
537
781
  )
@@ -544,24 +788,38 @@ const CCalendar = defineComponent({
544
788
  'tr',
545
789
  {},
546
790
  row.map((year) => {
791
+ const date = new Date(Date.UTC(year, 0, 1))
792
+ const isDisabled = isDateDisabled(
793
+ date,
794
+ minDate.value,
795
+ maxDate.value,
796
+ props.disabledDates,
797
+ )
547
798
  return h(
548
799
  'td',
549
800
  {
550
- class: 'calendar-cell year',
551
- onClick: () => {
552
- calendarDate.value = new Date(
553
- year,
554
- date.getMonth() - addMonths,
555
- date.getDate(),
556
- )
557
- view.value = 'months'
558
- },
559
- onKeydown: (event: KeyboardEvent) =>
560
- handleYearKeyDown(
561
- event,
562
- new Date(year, date.getMonth() - addMonths, date.getDate()),
563
- ),
564
- tabindex: 0,
801
+ class: [
802
+ 'calendar-cell year',
803
+ {
804
+ disabled: isDisabled,
805
+ selected: isDateSelected(date, startDate.value, endDate.value),
806
+ 'range-hover':
807
+ props.selectionType === 'year' &&
808
+ (hoverDate && selectEndDate
809
+ ? isDateInRange(date, startDate.value, hoverDate.value)
810
+ : isDateInRange(date, hoverDate.value, endDate.value)),
811
+ range: isDateInRange(date, startDate.value, endDate.value),
812
+ },
813
+ ],
814
+ tabindex: !isDisabled ? 0 : -1,
815
+ ...(!isDisabled && {
816
+ onBlur: () => handleCalendarMouseLeave(),
817
+ onClick: () => handleCalendarClick(date),
818
+ onFocus: () => handleCalendarMouseEnter(date),
819
+ onKeydown: (event: KeyboardEvent) => handleCalendarKeyDown(event, date),
820
+ onMouseEnter: () => handleCalendarMouseEnter(date),
821
+ onMouseLeave: () => handleCalendarMouseLeave(),
822
+ }),
565
823
  },
566
824
  h('div', { class: 'calendar-cell-inner' }, year),
567
825
  )
@@ -572,17 +830,7 @@ const CCalendar = defineComponent({
572
830
  ])
573
831
  }
574
832
 
575
- const Navigation = (addMonths: number) => {
576
- let date = calendarDate.value
577
-
578
- if (addMonths !== 0) {
579
- date = new Date(
580
- calendarDate.value.getFullYear(),
581
- calendarDate.value.getMonth() + addMonths,
582
- 1,
583
- )
584
- }
585
-
833
+ const Navigation = (_calendarDate: Date) => {
586
834
  return h('div', { class: 'calendar-nav' }, [
587
835
  props.navigation &&
588
836
  h(
@@ -645,7 +893,7 @@ const CCalendar = defineComponent({
645
893
  if (props.navigation) view.value = 'months'
646
894
  },
647
895
  },
648
- () => date.toLocaleDateString(props.locale, { month: 'long' }),
896
+ () => _calendarDate.toLocaleDateString(props.locale, { month: 'long' }),
649
897
  ),
650
898
  h(
651
899
  CButton,
@@ -657,7 +905,7 @@ const CCalendar = defineComponent({
657
905
  },
658
906
  ...(props.navYearFirst && { style: { order: '-1' } }),
659
907
  },
660
- () => date.toLocaleDateString(props.locale, { year: 'numeric' }),
908
+ () => _calendarDate.toLocaleDateString(props.locale, { year: 'numeric' }),
661
909
  ),
662
910
  ],
663
911
  ),
@@ -709,11 +957,28 @@ const CCalendar = defineComponent({
709
957
  }
710
958
 
711
959
  return () =>
712
- h('div', { class: 'calendars' }, [
713
- Array.from({ length: props.calendars }, (_, index) =>
714
- h('div', { class: ['calendar', view.value] }, [Navigation(index), Calendar(index)]),
715
- ),
716
- ])
960
+ h(
961
+ 'div',
962
+ {
963
+ class: [
964
+ 'calendars',
965
+ {
966
+ [`select-${props.selectionType}`]: props.selectionType && view.value === 'days',
967
+ 'show-week-numbers': props.showWeekNumber,
968
+ },
969
+ ],
970
+ ref: calendarRef,
971
+ },
972
+ [
973
+ Array.from({ length: props.calendars }, (_, index) => {
974
+ const _calendarDate = getCalendarDate(calendarDate.value, index, view.value)
975
+ return h('div', { class: ['calendar', view.value] }, [
976
+ Navigation(_calendarDate),
977
+ Calendar(_calendarDate),
978
+ ])
979
+ }),
980
+ ],
981
+ )
717
982
  },
718
983
  })
719
984