@coreui/vue-pro 4.1.4 → 4.3.0-beta.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 (64) hide show
  1. package/README.md +1 -1
  2. package/dist/components/button/CButton.d.ts +29 -2
  3. package/dist/components/calendar/CCalendar.d.ts +185 -0
  4. package/dist/components/calendar/index.d.ts +6 -0
  5. package/dist/components/date-picker/CDatePicker.d.ts +406 -0
  6. package/dist/components/date-picker/index.d.ts +6 -0
  7. package/dist/components/date-range-picker/CDateRangePicker.d.ts +480 -0
  8. package/dist/components/date-range-picker/index.d.ts +6 -0
  9. package/dist/components/dropdown/CDropdown.d.ts +25 -0
  10. package/dist/components/dropdown/CDropdownToggle.d.ts +35 -1
  11. package/dist/components/index.d.ts +5 -0
  12. package/dist/components/multi-select/CMultiSelect.d.ts +2 -2
  13. package/dist/components/picker/CPicker.d.ts +11 -0
  14. package/dist/components/picker/index.d.ts +6 -0
  15. package/dist/components/popover/CPopover.d.ts +1 -1
  16. package/dist/components/sidebar/CSidebar.d.ts +1 -1
  17. package/dist/components/smart-table/CSmartTable.d.ts +35 -99
  18. package/dist/components/smart-table/CSmartTableInterface.d.ts +3 -3
  19. package/dist/components/time-picker/CTimePicker.d.ts +10 -0
  20. package/dist/components/time-picker/CTimePickerRollCol.d.ts +27 -0
  21. package/dist/components/time-picker/index.d.ts +6 -0
  22. package/dist/components/toast/CToast.d.ts +1 -1
  23. package/dist/index.es.js +3726 -1646
  24. package/dist/index.es.js.map +1 -1
  25. package/dist/index.js +3734 -1644
  26. package/dist/index.js.map +1 -1
  27. package/dist/utils/calendar.d.ts +21 -0
  28. package/dist/utils/time.d.ts +17 -0
  29. package/package.json +9 -9
  30. package/src/components/accordion/CAccordionButton.ts +1 -0
  31. package/src/components/accordion/__tests__/__snapshots__/CAccordionButton.spec.ts.snap +1 -1
  32. package/src/components/accordion/__tests__/__snapshots__/CAccordionHeader.spec.ts.snap +1 -1
  33. package/src/components/button/CButton.ts +30 -1
  34. package/src/components/button/__tests__/__snapshots__/CButton.spec.ts.snap +1 -1
  35. package/src/components/calendar/CCalendar.ts +546 -0
  36. package/src/components/calendar/index.ts +10 -0
  37. package/src/components/close-button/CCloseButton.ts +4 -1
  38. package/src/components/date-picker/CDatePicker.ts +243 -0
  39. package/src/components/date-picker/index.ts +10 -0
  40. package/src/components/date-range-picker/CDateRangePicker.ts +635 -0
  41. package/src/components/date-range-picker/index.ts +10 -0
  42. package/src/components/dropdown/CDropdown.ts +48 -49
  43. package/src/components/dropdown/CDropdownMenu.ts +52 -7
  44. package/src/components/dropdown/CDropdownToggle.ts +93 -29
  45. package/src/components/dropdown/__tests__/CDropdownMenu.spec.ts +7 -7
  46. package/src/components/dropdown/__tests__/CDropdownToggle.spec.ts +4 -5
  47. package/src/components/dropdown/__tests__/__snapshots__/CDropdownToggle.spec.ts.snap +2 -2
  48. package/src/components/form/CFormCheck.ts +2 -1
  49. package/src/components/form/CFormSwitch.ts +1 -7
  50. package/src/components/form/__tests__/__snapshots__/CFormCheck.spec.ts.snap +2 -8
  51. package/src/components/index.ts +5 -0
  52. package/src/components/modal/__tests__/__snapshots__/CModal.spec.ts.snap +2 -1
  53. package/src/components/pagination/CSmartPagination.ts +4 -4
  54. package/src/components/picker/CPicker.ts +220 -0
  55. package/src/components/picker/index.ts +10 -0
  56. package/src/components/sidebar/__tests__/__snapshots__/CSidebar.spec.ts.snap +8 -2
  57. package/src/components/smart-table/CSmartTable.ts +17 -49
  58. package/src/components/smart-table/CSmartTableInterface.ts +5 -3
  59. package/src/components/time-picker/CTimePicker.ts +410 -0
  60. package/src/components/time-picker/CTimePickerRollCol.ts +58 -0
  61. package/src/components/time-picker/index.ts +10 -0
  62. package/src/components/toast/__tests__/__snapshots__/CToastClose.spec.ts.snap +1 -1
  63. package/src/utils/calendar.ts +193 -0
  64. package/src/utils/time.ts +58 -0
@@ -0,0 +1,410 @@
1
+ import { defineComponent, h, ref, watch } from 'vue'
2
+
3
+ import { CFormInput, CFormSelect, CInputGroup, CInputGroupText } from '../form/'
4
+ import { CPicker } from '../picker'
5
+ import { CTimePickerRollCol } from './CTimePickerRollCol'
6
+
7
+ import {
8
+ convert12hTo24h,
9
+ convertTimeToDate,
10
+ getAmPm,
11
+ getListOfHours,
12
+ getMinutesOrSeconds,
13
+ getSelectedHour,
14
+ getSelectedMinutes,
15
+ getSelectedSeconds,
16
+ isAmPm,
17
+ isValidTime,
18
+ } from '../../utils/time'
19
+
20
+ import { Color } from '../props'
21
+
22
+ const CTimePicker = defineComponent({
23
+ name: 'CTimePicker',
24
+ props: {
25
+ ...CPicker.props,
26
+ /**
27
+ * Toggle visibility or set the content of cancel button.
28
+ */
29
+ cancelButton: {
30
+ type: [Boolean, String],
31
+ default: 'Cancel',
32
+ },
33
+ /**
34
+ * Sets the color context of the cancel button to one of CoreUI’s themed colors.
35
+ *
36
+ * @values 'primary', 'secondary', 'success', 'danger', 'warning', 'info', 'dark', 'light'
37
+ */
38
+ cancelButtonColor: {
39
+ ...Color,
40
+ default: 'primary',
41
+ },
42
+ /**
43
+ * Size the cancel button small or large.
44
+ *
45
+ * @values 'sm', 'lg'
46
+ */
47
+ cancelButtonSize: {
48
+ type: String,
49
+ default: 'sm',
50
+ validator: (value: string) => {
51
+ return ['sm', 'lg'].includes(value)
52
+ },
53
+ },
54
+ /**
55
+ * Set the cancel button variant to an outlined button or a ghost button.
56
+ *
57
+ * @values 'ghost', 'outline'
58
+ */
59
+ cancelButtonVariant: {
60
+ type: String,
61
+ default: 'ghost',
62
+ validator: (value: string) => {
63
+ return ['ghost', 'outline'].includes(value)
64
+ },
65
+ },
66
+ /**
67
+ * Toggle visibility of the cleaner button.
68
+ */
69
+ cleaner: {
70
+ type: Boolean,
71
+ default: true,
72
+ },
73
+ /**
74
+ * Toggle visibility or set the content of confirm button.
75
+ */
76
+ confirmButton: {
77
+ type: [Boolean, String],
78
+ default: 'OK',
79
+ },
80
+ /**
81
+ * Sets the color context of the confirm button to one of CoreUI’s themed colors.
82
+ *
83
+ * @values 'primary', 'secondary', 'success', 'danger', 'warning', 'info', 'dark', 'light'
84
+ */
85
+ confirmButtonColor: {
86
+ ...Color,
87
+ default: 'primary',
88
+ },
89
+ /**
90
+ * Size the confirm button small or large.
91
+ *
92
+ * @values 'sm', 'lg'
93
+ */
94
+ confirmButtonSize: {
95
+ type: String,
96
+ default: 'sm',
97
+ validator: (value: string) => {
98
+ return ['sm', 'lg'].includes(value)
99
+ },
100
+ },
101
+ /**
102
+ * Set the confirm button variant to an outlined button or a ghost button.
103
+ *
104
+ * @values 'ghost', 'outline'
105
+ */
106
+ confirmButtonVariant: {
107
+ type: String,
108
+ validator: (value: string) => {
109
+ return ['ghost', 'outline'].includes(value)
110
+ },
111
+ },
112
+ /**
113
+ * Toggle visibility or set the content of the input indicator.
114
+ */
115
+ indicator: {
116
+ type: Boolean,
117
+ default: true,
118
+ },
119
+ /**
120
+ * Toggle the readonly state for the component.
121
+ */
122
+ inputReadOnly: Boolean,
123
+ /**
124
+ * Sets the default locale for components. If not set, it is inherited from the navigator.language.
125
+ */
126
+ locale: {
127
+ type: String,
128
+ defalut: 'default',
129
+ },
130
+ /**
131
+ * Specifies a short hint that is visible in the input.
132
+ */
133
+ placeholder: {
134
+ type: String,
135
+ default: 'Select time',
136
+ },
137
+ /**
138
+ * Size the component small or large.
139
+ *
140
+ * @values 'sm', 'lg'
141
+ */
142
+ size: {
143
+ type: String,
144
+ default: undefined,
145
+ validator: (value: string) => {
146
+ return ['sm', 'lg'].includes(value)
147
+ },
148
+ },
149
+ /**
150
+ * Initial selected time.
151
+ */
152
+ time: {
153
+ type: [Date, String],
154
+ },
155
+ /**
156
+ * Set the time picker variant to a roll or select.
157
+ *
158
+ * @values 'roll', 'select'
159
+ */
160
+ variant: {
161
+ type: String,
162
+ default: 'roll',
163
+ validator: (value: string) => {
164
+ return ['roll', 'select'].includes(value)
165
+ },
166
+ },
167
+ },
168
+ emits: [
169
+ /**
170
+ * Callback fired when the time changed.
171
+ */
172
+ 'change',
173
+ /**
174
+ * Callback fired when the component requests to be hidden.
175
+ */
176
+ 'hide',
177
+ /**
178
+ * Callback fired when the component requests to be shown.
179
+ */
180
+ 'show',
181
+ ],
182
+ setup(props, { emit, slots }) {
183
+ const date = ref<Date | null>(convertTimeToDate(props.time))
184
+ const initialDate = ref<Date | null>(null)
185
+ const ampm = ref<'am' | 'pm'>(date.value ? getAmPm(new Date(date.value), props.locale) : 'am')
186
+
187
+ watch(
188
+ () => props.time,
189
+ () => {
190
+ date.value = convertTimeToDate(props.time)
191
+ },
192
+ )
193
+
194
+ watch(date, () => {
195
+ if (date.value) {
196
+ ampm.value = getAmPm(new Date(date.value), props.locale)
197
+ }
198
+ })
199
+
200
+ const handleClear = (event: Event) => {
201
+ event.stopPropagation()
202
+ date.value = null
203
+ }
204
+
205
+ const handleTimeChange = (set: 'hours' | 'minutes' | 'seconds' | 'toggle', value: string) => {
206
+ const _date = date.value || new Date('1970-01-01')
207
+
208
+ if (set === 'toggle') {
209
+ if (value === 'am') {
210
+ _date.setHours(_date.getHours() - 12)
211
+ }
212
+ if (value === 'pm') {
213
+ _date.setHours(_date.getHours() + 12)
214
+ }
215
+ }
216
+
217
+ if (set === 'hours') {
218
+ if (isAmPm(props.locale)) {
219
+ _date.setHours(convert12hTo24h(ampm.value, parseInt(value)))
220
+ } else {
221
+ _date.setHours(parseInt(value))
222
+ }
223
+ }
224
+
225
+ if (set === 'minutes') {
226
+ _date.setMinutes(parseInt(value))
227
+ }
228
+
229
+ if (set === 'seconds') {
230
+ _date.setSeconds(parseInt(value))
231
+ }
232
+
233
+ date.value = new Date(_date)
234
+ emit('change', _date.toTimeString(), _date.toLocaleTimeString(), _date)
235
+ }
236
+
237
+ const InputGroup = () =>
238
+ h(CInputGroup, { class: 'picker-input-group', size: props.size }, () => [
239
+ h(CFormInput, {
240
+ disabled: props.disabled,
241
+ onInput: (event) => {
242
+ if (isValidTime(event.target.value)) {
243
+ date.value = convertTimeToDate(event.target.value)
244
+ }
245
+ },
246
+ placeholder: props.placeholder,
247
+ readonly: props.inputReadOnly,
248
+ value: date.value ? date.value.toLocaleTimeString(props.locale) : '',
249
+ }),
250
+ (props.indicator || props.cleaner) &&
251
+ h(CInputGroupText, {}, () => [
252
+ props.indicator &&
253
+ h(
254
+ 'span',
255
+ {
256
+ class: 'picker-input-group-indicator',
257
+ },
258
+ slots.indicator
259
+ ? slots.indicator()
260
+ : h('span', { class: 'picker-input-group-icon time-picker-input-icon' }),
261
+ ),
262
+ props.cleaner &&
263
+ h(
264
+ 'span',
265
+ {
266
+ class: 'picker-input-group-cleaner',
267
+ onClick: (event: Event) => handleClear(event),
268
+ role: 'button',
269
+ },
270
+ slots.cleaner
271
+ ? slots.cleaner()
272
+ : h('span', { class: 'picker-input-group-icon time-picker-cleaner-icon' }),
273
+ ),
274
+ ]),
275
+ ])
276
+
277
+ const TimePickerSelect = () => [
278
+ h('span', { class: 'time-picker-inline-icon' }),
279
+ h(CFormSelect, {
280
+ disabled: props.disabled,
281
+ options: getListOfHours(props.locale).map((option) => {
282
+ return {
283
+ value: option.value.toString(),
284
+ label: option.label,
285
+ }
286
+ }),
287
+ onChange: (event) => handleTimeChange('hours', event.target.value),
288
+ ...(date.value && { value: getSelectedHour(date.value, props.locale) }),
289
+ }),
290
+ ':',
291
+ h(CFormSelect, {
292
+ disabled: props.disabled,
293
+ options: Array.from({ length: 60 }, (_, i) => {
294
+ return {
295
+ value: i.toString(),
296
+ label: i.toLocaleString(props.locale).padStart(2, (0).toLocaleString(props.locale)),
297
+ }
298
+ }),
299
+ onChange: (event) => handleTimeChange('minutes', event.target.value),
300
+ ...(date.value && { value: getSelectedMinutes(date.value) }),
301
+ }),
302
+ ':',
303
+ h(CFormSelect, {
304
+ disabled: props.disabled,
305
+ options: Array.from({ length: 60 }, (_, i) => {
306
+ return {
307
+ value: i.toString(),
308
+ label: i.toLocaleString(props.locale).padStart(2, (0).toLocaleString(props.locale)),
309
+ }
310
+ }),
311
+ onChange: (event) => handleTimeChange('seconds', event.target.value),
312
+ ...(date.value && { value: getSelectedSeconds(date.value) }),
313
+ }),
314
+ isAmPm(props.locale) &&
315
+ h(CFormSelect, {
316
+ disabled: props.disabled,
317
+ options: [
318
+ { value: 'am', label: 'AM' },
319
+ { value: 'pm', label: 'PM' },
320
+ ],
321
+ onChange: (event) => handleTimeChange('toggle', event.target.value),
322
+ value: ampm.value,
323
+ }),
324
+ ]
325
+
326
+ const TimePickerRoll = () => [
327
+ h(CTimePickerRollCol, {
328
+ elements: getListOfHours(props.locale),
329
+ onClick: (index: number) => handleTimeChange('hours', index.toString()),
330
+ selected: getSelectedHour(date.value, props.locale),
331
+ }),
332
+ h(CTimePickerRollCol, {
333
+ elements: getMinutesOrSeconds(props.locale),
334
+ onClick: (index: number) => handleTimeChange('minutes', index.toString()),
335
+ selected: getSelectedMinutes(date.value),
336
+ }),
337
+ h(CTimePickerRollCol, {
338
+ elements: getMinutesOrSeconds(props.locale),
339
+ onClick: (index: number) => handleTimeChange('seconds', index.toString()),
340
+ selected: getSelectedSeconds(date.value),
341
+ }),
342
+ isAmPm(props.locale) &&
343
+ h(CTimePickerRollCol, {
344
+ elements: [
345
+ { value: 'am', label: 'AM' },
346
+ { value: 'pm', label: 'PM' },
347
+ ],
348
+ onClick: (value: string) => handleTimeChange('toggle', value),
349
+ selected: ampm.value,
350
+ }),
351
+ ]
352
+
353
+ return () =>
354
+ h(
355
+ CPicker,
356
+ {
357
+ cancelButton: props.cancelButton,
358
+ cancelButtonColor: props.cancelButtonColor,
359
+ cancelButtonSize: props.cancelButtonSize,
360
+ cancelButtonVariant: props.cancelButtonVariant,
361
+ class: 'time-picker',
362
+ confirmButton: props.confirmButton,
363
+ confirmButtonColor: props.confirmButtonColor,
364
+ confirmButtonSize: props.confirmButtonSize,
365
+ confirmButtonVariant: props.confirmButtonVariant,
366
+ container: props.container,
367
+ disabled: props.disabled,
368
+ footer: true,
369
+ onCancel: () => {
370
+ if (initialDate.value) {
371
+ date.value = new Date(initialDate.value)
372
+ }
373
+ },
374
+ onHide: () => {
375
+ emit('hide')
376
+ },
377
+ onShow: () => {
378
+ if (date.value) {
379
+ initialDate.value = new Date(date.value)
380
+ }
381
+
382
+ emit('show')
383
+ },
384
+ },
385
+ {
386
+ ...(slots.cancelButton && {
387
+ cancelButton: () => slots.cancelButton && slots.cancelButton(),
388
+ }),
389
+ ...(slots.confirmButton && {
390
+ confirmButton: () => slots.confirmButton && slots.confirmButton(),
391
+ }),
392
+ toggler: () => InputGroup(),
393
+ default: () =>
394
+ h(
395
+ 'div',
396
+ {
397
+ class: [
398
+ 'time-picker-body',
399
+ {
400
+ ['time-picker-roll']: props.variant === 'roll',
401
+ },
402
+ ],
403
+ },
404
+ props.variant === 'select' ? TimePickerSelect() : TimePickerRoll(),
405
+ ),
406
+ },
407
+ )
408
+ },
409
+ })
410
+ export { CTimePicker }
@@ -0,0 +1,58 @@
1
+ import { defineComponent, h, onUpdated, PropType, ref } from 'vue'
2
+
3
+ export interface Element {
4
+ value: number | string
5
+ label: number | string
6
+ }
7
+
8
+ const CTimePickerRollCol = defineComponent({
9
+ name: 'CTimePickerRollCol',
10
+ props: {
11
+ elements: {
12
+ type: Array as PropType<Element[]>,
13
+ required: true,
14
+ },
15
+ selected: {
16
+ type: [Number, String],
17
+ },
18
+ },
19
+ emits: ['click'],
20
+ setup(props, { emit }) {
21
+ const init = ref(true)
22
+ const colRef = ref<HTMLDivElement>()
23
+
24
+ onUpdated(() => {
25
+ const nodeEl = colRef.value?.querySelector('.selected')
26
+ if (nodeEl && nodeEl instanceof HTMLElement) {
27
+ colRef.value?.scrollTo({
28
+ top: nodeEl.offsetTop,
29
+ behavior: init.value ? 'auto' : 'smooth',
30
+ })
31
+ }
32
+ init.value = false
33
+ })
34
+
35
+ return () =>
36
+ h(
37
+ 'div',
38
+ { class: 'time-picker-roll-col', ref: colRef },
39
+ props.elements.map((element) => {
40
+ return h(
41
+ 'div',
42
+ {
43
+ class: [
44
+ 'time-picker-roll-cell',
45
+ {
46
+ selected: element.value === props.selected,
47
+ },
48
+ ],
49
+ onClick: () => emit('click', element.value),
50
+ role: 'button',
51
+ },
52
+ element.label,
53
+ )
54
+ }),
55
+ )
56
+ },
57
+ })
58
+ export { CTimePickerRollCol }
@@ -0,0 +1,10 @@
1
+ import { App } from 'vue'
2
+ import { CTimePicker } from './CTimePicker'
3
+
4
+ const CTimePickerPlugin = {
5
+ install: (app: App): void => {
6
+ app.component(CTimePicker.name, CTimePicker)
7
+ },
8
+ }
9
+
10
+ export { CTimePicker, CTimePickerPlugin }
@@ -1,5 +1,5 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`Customize CToastClose component renders correctly 1`] = `"<button class=\\"btn btn-undefined\\">Default slot</button>"`;
3
+ exports[`Customize CToastClose component renders correctly 1`] = `"<button class=\\"btn btn-undefined\\" type=\\"button\\">Default slot</button>"`;
4
4
 
5
5
  exports[`Loads and display CToastClose component renders correctly 1`] = `"<button class=\\"btn btn-close\\" aria-label=\\"Close\\"></button>"`;
@@ -0,0 +1,193 @@
1
+ export const convertToLocalDate = (d: Date, locale: string, options = {}) =>
2
+ d.toLocaleDateString(locale, options)
3
+
4
+ export const convertToLocalTime = (d: Date, locale: string, options = {}) =>
5
+ d.toLocaleTimeString(locale, options)
6
+
7
+ export const createGroupsInArray = (arr: any[], numberOfGroups: number) => {
8
+ const perGroup = Math.ceil(arr.length / numberOfGroups)
9
+ return new Array(numberOfGroups)
10
+ .fill('')
11
+ .map((_, i) => arr.slice(i * perGroup, (i + 1) * perGroup))
12
+ }
13
+
14
+ export const getCurrentYear = () => new Date().getFullYear()
15
+
16
+ export const getCurrentMonth = () => new Date().getMonth()
17
+
18
+ export const getMonthName = (month: number, locale: string) => {
19
+ const d = new Date()
20
+ d.setDate(1)
21
+ d.setMonth(month)
22
+ return d.toLocaleString(locale, { month: 'long' })
23
+ }
24
+
25
+ export const getMonthsNames = (locale: string) => {
26
+ const months = []
27
+ const d = new Date()
28
+ d.setDate(1)
29
+
30
+ for (let i = 0; i < 12; i++) {
31
+ d.setMonth(i)
32
+ months.push(d.toLocaleString(locale, { month: 'short' }))
33
+ }
34
+
35
+ return months
36
+ }
37
+
38
+ export const getYears = (year: number) => {
39
+ const years = []
40
+ for (let _year = year - 6; _year < year + 6; _year++) {
41
+ years.push(_year)
42
+ }
43
+
44
+ return years
45
+ }
46
+
47
+ const getLeadingDays = (year: number, month: number, firstDayOfWeek: number) => {
48
+ // 0: sunday
49
+ // 1: monday
50
+ const dates = []
51
+ const d = new Date(year, month)
52
+ const y = d.getFullYear()
53
+ const m = d.getMonth()
54
+ const firstWeekday = new Date(y, m, 1).getDay()
55
+ let leadingDays = 6 - (6 - firstWeekday) - firstDayOfWeek
56
+
57
+ if (firstDayOfWeek) {
58
+ leadingDays = leadingDays < 0 ? 7 + leadingDays : leadingDays
59
+ }
60
+
61
+ for (let i = leadingDays * -1; i < 0; i++) {
62
+ dates.push({
63
+ date: new Date(y, m, i + 1),
64
+ month: 'previous',
65
+ })
66
+ }
67
+
68
+ return dates
69
+ }
70
+
71
+ const getMonthDays = (year: number, month: number) => {
72
+ const dates = []
73
+ const lastDay = new Date(year, month + 1, 0).getDate()
74
+ for (let i = 1; i <= lastDay; i++) {
75
+ dates.push({
76
+ date: new Date(year, month, i),
77
+ month: 'current',
78
+ })
79
+ }
80
+ return dates
81
+ }
82
+
83
+ const getTrailingDays = (
84
+ year: number,
85
+ month: number,
86
+ leadingDays: { date: Date; month: string }[],
87
+ monthDays: { date: Date; month: string }[],
88
+ ) => {
89
+ const dates = []
90
+ const days = 42 - (leadingDays.length + monthDays.length)
91
+ for (let i = 1; i <= days; i++) {
92
+ dates.push({
93
+ date: new Date(year, month + 1, i),
94
+ month: 'next',
95
+ })
96
+ }
97
+ return dates
98
+ }
99
+
100
+ export const getMonthDetails = (year: number, month: number, firstDayOfWeek: number) => {
101
+ const daysPrevMonth = getLeadingDays(year, month, firstDayOfWeek)
102
+ const daysThisMonth = getMonthDays(year, month)
103
+ const daysNextMonth = getTrailingDays(year, month, daysPrevMonth, daysThisMonth)
104
+ const days = [...daysPrevMonth, ...daysThisMonth, ...daysNextMonth]
105
+
106
+ const weeks: { date: Date; month: string }[][] = []
107
+
108
+ days.forEach((day, index) => {
109
+ if (index % 7 === 0 || weeks.length === 0) {
110
+ weeks.push([])
111
+ }
112
+ weeks[weeks.length - 1].push(day)
113
+ })
114
+
115
+ return weeks
116
+ }
117
+
118
+ export const isDateDisabled = (
119
+ date: Date,
120
+ min?: Date | null,
121
+ max?: Date | null,
122
+ dates?: Date[] | Date[][],
123
+ ) => {
124
+ let disabled
125
+ if (dates) {
126
+ dates.forEach((_date: Date | Date[]) => {
127
+ if (Array.isArray(_date)) {
128
+ if (isDateInRange(date, _date[0], _date[1])) {
129
+ disabled = true
130
+ }
131
+ }
132
+ if (_date instanceof Date) {
133
+ if (isSameDateAs(date, _date)) {
134
+ disabled = true
135
+ }
136
+ }
137
+ })
138
+ }
139
+ if (min && date < min) {
140
+ disabled = true
141
+ }
142
+
143
+ if (max && date > max) {
144
+ disabled = true
145
+ }
146
+ return disabled
147
+ }
148
+
149
+ export const isDateInRange = (date: Date, start: Date | null, end: Date | null) => {
150
+ return start && end && start <= date && date <= end
151
+ }
152
+
153
+ export const isDateSelected = (date: Date, start: Date | null, end: Date | null) => {
154
+ return (start && isSameDateAs(start, date)) || (end && isSameDateAs(end, date))
155
+ }
156
+
157
+ export const isEndDate = (date: Date, start: Date | null, end: Date | null) => {
158
+ return start && end && isSameDateAs(end, date) && start < end
159
+ }
160
+
161
+ export const isLastDayOfMonth = (date: Date) => {
162
+ const test = new Date(date.getTime())
163
+ const month = test.getMonth()
164
+
165
+ test.setDate(test.getDate() + 1)
166
+ return test.getMonth() !== month
167
+ }
168
+
169
+ export const isSameDateAs = (date: Date, date2: Date) => {
170
+ return (
171
+ date.getDate() == date2.getDate() &&
172
+ date.getMonth() == date2.getMonth() &&
173
+ date.getFullYear() == date2.getFullYear()
174
+ )
175
+ }
176
+
177
+ export const isStartDate = (date: Date, start: Date | null, end: Date | null) => {
178
+ return start && end && isSameDateAs(start, date) && start < end
179
+ }
180
+
181
+ export const isToday = (date: Date) => {
182
+ const today = new Date()
183
+ return (
184
+ date.getDate() == today.getDate() &&
185
+ date.getMonth() == today.getMonth() &&
186
+ date.getFullYear() == today.getFullYear()
187
+ )
188
+ }
189
+
190
+ export const isValidDate = (date: string) => {
191
+ const d = new Date(date)
192
+ return d instanceof Date && d.getTime()
193
+ }