bge-ui 1.3.4 → 1.3.6

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 (135) hide show
  1. package/dist/datePicker/components/ActionRow.vue.d.ts +1051 -0
  2. package/dist/datePicker/components/Common/ArrowBtn.vue.d.ts +29 -0
  3. package/dist/datePicker/components/Common/InstanceWrap.vue.d.ts +29 -0
  4. package/dist/datePicker/components/Common/SelectionOverlay.vue.d.ts +55 -0
  5. package/dist/datePicker/components/DatePicker/DatePicker.vue.d.ts +1114 -0
  6. package/dist/datePicker/components/DatePicker/DpCalendar.vue.d.ts +1085 -0
  7. package/dist/datePicker/components/DatePicker/DpHeader.vue.d.ts +1103 -0
  8. package/dist/datePicker/components/DatePicker/date-picker.d.ts +35 -0
  9. package/dist/datePicker/components/DatepickerInput.vue.d.ts +1008 -0
  10. package/dist/datePicker/components/DatepickerMenu.vue.d.ts +1061 -0
  11. package/dist/datePicker/components/Icons/CalendarIcon.d.ts +9 -0
  12. package/dist/datePicker/components/Icons/CancelIcon.d.ts +9 -0
  13. package/dist/datePicker/components/Icons/ChevronDownIcon.d.ts +9 -0
  14. package/dist/datePicker/components/Icons/ChevronLeftIcon.d.ts +9 -0
  15. package/dist/datePicker/components/Icons/ChevronRightIcon.d.ts +9 -0
  16. package/dist/datePicker/components/Icons/ChevronUpIcon.d.ts +9 -0
  17. package/dist/datePicker/components/Icons/ClockIcon.d.ts +9 -0
  18. package/dist/datePicker/components/Icons/index.d.ts +7 -0
  19. package/dist/datePicker/components/MonthPicker/MonthPicker.vue.d.ts +1071 -0
  20. package/dist/datePicker/components/MonthPicker/month-picker.d.ts +34 -0
  21. package/dist/datePicker/components/QuarterPicker/QuarterPicker.vue.d.ts +1043 -0
  22. package/dist/datePicker/components/QuarterPicker/quarter-picker.d.ts +25 -0
  23. package/dist/datePicker/components/TimePicker/TimeInput.vue.d.ts +1116 -0
  24. package/dist/datePicker/components/TimePicker/TimePicker.vue.d.ts +1087 -0
  25. package/dist/datePicker/components/TimePicker/TimePickerSolo.vue.d.ts +1036 -0
  26. package/dist/datePicker/components/TimePicker/time-picker-utils.d.ts +15 -0
  27. package/dist/datePicker/components/TimePicker/time-picker.d.ts +13 -0
  28. package/dist/datePicker/components/YearPicker/YearPicker.vue.d.ts +1040 -0
  29. package/dist/datePicker/components/YearPicker/year-picker.d.ts +9 -0
  30. package/dist/datePicker/components/shared/YearModePicker.vue.d.ts +1075 -0
  31. package/dist/datePicker/components/shared/month-quarter-picker.d.ts +29 -0
  32. package/dist/datePicker/composables/arrow-navigate.d.ts +26 -0
  33. package/dist/datePicker/composables/calendar-class.d.ts +8 -0
  34. package/dist/datePicker/composables/common.d.ts +6 -0
  35. package/dist/datePicker/composables/defaults.d.ts +37 -0
  36. package/dist/datePicker/composables/external-internal-mapper.d.ts +14 -0
  37. package/dist/datePicker/composables/flow.d.ts +10 -0
  38. package/dist/datePicker/composables/index.d.ts +14 -0
  39. package/dist/datePicker/composables/model.d.ts +17 -0
  40. package/dist/datePicker/composables/month-year.d.ts +10 -0
  41. package/dist/datePicker/composables/position.d.ts +25 -0
  42. package/dist/datePicker/composables/shared.d.ts +12 -0
  43. package/dist/datePicker/composables/slots.d.ts +10 -0
  44. package/dist/datePicker/composables/state.d.ts +8 -0
  45. package/dist/datePicker/composables/transition.d.ts +7 -0
  46. package/dist/datePicker/composables/validation.d.ts +12 -0
  47. package/dist/datePicker/constants/index.d.ts +43 -0
  48. package/dist/datePicker/datePicker.vue.d.ts +1006 -0
  49. package/dist/datePicker/directives/clickOutside.d.ts +2 -0
  50. package/dist/datePicker/index.vue.d.ts +1012 -0
  51. package/dist/datePicker/interfaces.d.ts +323 -0
  52. package/dist/datePicker/props.d.ts +865 -0
  53. package/dist/datePicker/utils/date-utils.d.ts +45 -0
  54. package/dist/datePicker/utils/defaults.d.ts +42 -0
  55. package/dist/datePicker/utils/timezone.d.ts +8 -0
  56. package/dist/datePicker/utils/type-guard.d.ts +1 -0
  57. package/dist/datePicker/utils/util.d.ts +57 -0
  58. package/dist/dialog/index.vue.d.ts +6 -3
  59. package/dist/index.d.ts +2 -1
  60. package/dist/index.js +13008 -1250
  61. package/dist/style.css +1188 -1
  62. package/dist/tooltip/index.vue.d.ts +2 -2
  63. package/dist/tooltip/usePopper.d.ts +5 -5
  64. package/package.json +3 -2
  65. package/src/datePicker/components/ActionRow.vue +216 -0
  66. package/src/datePicker/components/Common/ArrowBtn.vue +42 -0
  67. package/src/datePicker/components/Common/InstanceWrap.vue +28 -0
  68. package/src/datePicker/components/Common/SelectionOverlay.vue +320 -0
  69. package/src/datePicker/components/DatePicker/DatePicker.vue +302 -0
  70. package/src/datePicker/components/DatePicker/DpCalendar.vue +405 -0
  71. package/src/datePicker/components/DatePicker/DpHeader.vue +332 -0
  72. package/src/datePicker/components/DatePicker/date-picker.ts +674 -0
  73. package/src/datePicker/components/DatepickerInput.vue +334 -0
  74. package/src/datePicker/components/DatepickerMenu.vue +424 -0
  75. package/src/datePicker/components/Icons/CalendarIcon.ts +40 -0
  76. package/src/datePicker/components/Icons/CancelIcon.ts +32 -0
  77. package/src/datePicker/components/Icons/ChevronDownIcon.ts +29 -0
  78. package/src/datePicker/components/Icons/ChevronLeftIcon.ts +29 -0
  79. package/src/datePicker/components/Icons/ChevronRightIcon.ts +29 -0
  80. package/src/datePicker/components/Icons/ChevronUpIcon.ts +29 -0
  81. package/src/datePicker/components/Icons/ClockIcon.ts +32 -0
  82. package/src/datePicker/components/Icons/index.ts +8 -0
  83. package/src/datePicker/components/MonthPicker/MonthPicker.vue +130 -0
  84. package/src/datePicker/components/MonthPicker/month-picker.ts +232 -0
  85. package/src/datePicker/components/QuarterPicker/QuarterPicker.vue +111 -0
  86. package/src/datePicker/components/QuarterPicker/quarter-picker.ts +153 -0
  87. package/src/datePicker/components/TimePicker/TimeInput.vue +477 -0
  88. package/src/datePicker/components/TimePicker/TimePicker.vue +265 -0
  89. package/src/datePicker/components/TimePicker/TimePickerSolo.vue +79 -0
  90. package/src/datePicker/components/TimePicker/time-picker-utils.ts +179 -0
  91. package/src/datePicker/components/TimePicker/time-picker.ts +112 -0
  92. package/src/datePicker/components/YearPicker/YearPicker.vue +70 -0
  93. package/src/datePicker/components/YearPicker/year-picker.ts +109 -0
  94. package/src/datePicker/components/shared/YearModePicker.vue +105 -0
  95. package/src/datePicker/components/shared/month-quarter-picker.ts +199 -0
  96. package/src/datePicker/composables/arrow-navigate.ts +191 -0
  97. package/src/datePicker/composables/calendar-class.ts +383 -0
  98. package/src/datePicker/composables/common.ts +25 -0
  99. package/src/datePicker/composables/defaults.ts +123 -0
  100. package/src/datePicker/composables/external-internal-mapper.ts +442 -0
  101. package/src/datePicker/composables/flow.ts +70 -0
  102. package/src/datePicker/composables/index.ts +14 -0
  103. package/src/datePicker/composables/model.ts +89 -0
  104. package/src/datePicker/composables/month-year.ts +72 -0
  105. package/src/datePicker/composables/position.ts +297 -0
  106. package/src/datePicker/composables/shared.ts +98 -0
  107. package/src/datePicker/composables/slots.ts +84 -0
  108. package/src/datePicker/composables/state.ts +25 -0
  109. package/src/datePicker/composables/transition.ts +18 -0
  110. package/src/datePicker/composables/validation.ts +312 -0
  111. package/src/datePicker/constants/index.ts +49 -0
  112. package/src/datePicker/datePicker.vue +554 -0
  113. package/src/datePicker/directives/clickOutside.ts +79 -0
  114. package/src/datePicker/index.vue +158 -0
  115. package/src/datePicker/interfaces.ts +404 -0
  116. package/src/datePicker/props.ts +173 -0
  117. package/src/datePicker/style/components/_ActionRow.scss +73 -0
  118. package/src/datePicker/style/components/_Calendar.scss +284 -0
  119. package/src/datePicker/style/components/_DatepickerInput.scss +109 -0
  120. package/src/datePicker/style/components/_DatepickerMenu.scss +213 -0
  121. package/src/datePicker/style/components/_MonthYearInput.scss +97 -0
  122. package/src/datePicker/style/components/_QuarterPicker.scss +53 -0
  123. package/src/datePicker/style/components/_SelectionOverlay.scss +142 -0
  124. package/src/datePicker/style/components/_TimeInput.scss +181 -0
  125. package/src/datePicker/style/components/_shared.scss +15 -0
  126. package/src/datePicker/style/main.scss +259 -0
  127. package/src/datePicker/utils/date-utils.ts +440 -0
  128. package/src/datePicker/utils/defaults.ts +327 -0
  129. package/src/datePicker/utils/timezone.ts +38 -0
  130. package/src/datePicker/utils/type-guard.ts +3 -0
  131. package/src/datePicker/utils/util.ts +322 -0
  132. package/src/dialog/index.vue +9 -0
  133. package/src/form/index.vue +2 -1
  134. package/src/index.ts +6 -2
  135. package/src/slider/index.vue +1 -1
@@ -0,0 +1,674 @@
1
+ import { computed, onMounted, ref, nextTick } from 'vue';
2
+ import {
3
+ add,
4
+ addDays,
5
+ addMonths,
6
+ getHours,
7
+ getMinutes,
8
+ getMonth,
9
+ getSeconds,
10
+ getYear,
11
+ set,
12
+ startOfWeek,
13
+ subMonths,
14
+ } from 'date-fns';
15
+
16
+ import {
17
+ getDate,
18
+ getDaysInBetween,
19
+ getNextMonthYear,
20
+ isDateBefore,
21
+ isDateEqual,
22
+ resetDateTime,
23
+ setDateTime,
24
+ } from '../../utils/date-utils';
25
+ import { useDefaults, useModel, useValidation } from '../../composables';
26
+ import { getMapDate, isNumNullish } from '../../utils/util';
27
+ import { isNumberArray } from '../../utils/type-guard';
28
+ import { useTimePickerUtils } from '../../components/TimePicker/time-picker-utils';
29
+ import {
30
+ checkRangeAutoApply,
31
+ getRangeWithFixedDate,
32
+ handleMultiDatesSelect,
33
+ setPresetDate,
34
+ } from '../../composables/shared';
35
+ import { FlowStep } from '../../constants';
36
+
37
+ import type { ICalendarDate, ICalendarDay, WeekStartNum, IMarker, VueEmit, TimeType } from '../../interfaces';
38
+ import type { UnwrapRef } from 'vue';
39
+ import type { PickerBasePropsType } from '../../props';
40
+ import { dateToTimezoneSafe } from '../../utils/timezone';
41
+
42
+ export const useDatePicker = (
43
+ props: PickerBasePropsType,
44
+ emit: VueEmit,
45
+ triggerCalendarTransition: (inst?: number) => void,
46
+ updateFlow: () => void,
47
+ ) => {
48
+ const tempRange = ref<Date[]>([]);
49
+ const lastScrollTime = ref(new Date());
50
+ const clickedDate = ref<ICalendarDay | undefined>();
51
+ const reMap = () => mapInternalModuleValues(props.isTextInputDate);
52
+
53
+ const { modelValue, calendars, time, today } = useModel(props, emit, reMap);
54
+ const {
55
+ defaultedMultiCalendars,
56
+ defaultedStartTime,
57
+ defaultedRange,
58
+ defaultedConfig,
59
+ defaultedTz,
60
+ propDates,
61
+ defaultedMultiDates,
62
+ } = useDefaults(props);
63
+ const { validateMonthYearInRange, isDisabled, isDateRangeAllowed, checkMinMaxRange } = useValidation(props);
64
+ const { updateTimeValues, getSetDateTime, setTime, assignStartTime, validateTime, disabledTimesConfig } =
65
+ useTimePickerUtils(props, time, modelValue, updateFlow);
66
+ // Get month based on the calendar instance
67
+ const month = computed(
68
+ () =>
69
+ (instance: number): number =>
70
+ calendars.value[instance] ? calendars.value[instance].month : 0,
71
+ );
72
+
73
+ // Get year based on the calendar instance
74
+ const year = computed(
75
+ () =>
76
+ (instance: number): number =>
77
+ calendars.value[instance] ? calendars.value[instance].year : 0,
78
+ );
79
+
80
+ const shouldUpdateMonthView = (isAction: boolean) => {
81
+ if (!defaultedConfig.value.keepViewOnOffsetClick || isAction) return true;
82
+ return !clickedDate.value;
83
+ };
84
+
85
+ // Any update for month or year value will go through this function
86
+ const setCalendarMonthYear = (
87
+ instance: number,
88
+ month: number | null,
89
+ year: number | null,
90
+ isAction: boolean = false,
91
+ ): void => {
92
+ if (shouldUpdateMonthView(isAction)) {
93
+ if (!calendars.value[instance]) {
94
+ calendars.value[instance] = { month: 0, year: 0 };
95
+ }
96
+ calendars.value[instance].month = isNumNullish(month) ? calendars.value[instance]?.month : month;
97
+ calendars.value[instance].year = isNumNullish(year) ? calendars.value[instance]?.year : year;
98
+ }
99
+ };
100
+
101
+ const selectOnAutoApply = () => {
102
+ if (props.autoApply) {
103
+ emit('select-date');
104
+ }
105
+ };
106
+
107
+ onMounted(() => {
108
+ if (!props.shadow) {
109
+ if (!modelValue.value) {
110
+ setStartDate();
111
+ if (defaultedStartTime.value) {
112
+ assignStartTime(defaultedStartTime.value);
113
+ }
114
+ }
115
+ mapInternalModuleValues(true);
116
+ if (props.focusStartDate && props.startDate) {
117
+ setStartDate();
118
+ }
119
+ }
120
+ });
121
+
122
+ const isFlowLastStep = computed(() => {
123
+ if (props.flow?.length && !props.partialFlow) {
124
+ return props.flowStep === props.flow.length;
125
+ }
126
+ return true;
127
+ });
128
+
129
+ const autoApply = (): void => {
130
+ if (props.autoApply && isFlowLastStep.value) {
131
+ emit('auto-apply', props.partialFlow ? props.flowStep !== props.flow.length : false);
132
+ }
133
+ };
134
+
135
+ const mapInternalModuleValues = (fromMount = false): void => {
136
+ if (modelValue.value) {
137
+ if (Array.isArray(modelValue.value)) {
138
+ tempRange.value = modelValue.value;
139
+ return assignExistingModelValueArr(fromMount);
140
+ }
141
+ return assignSingleValue(modelValue.value, fromMount);
142
+ }
143
+ if (defaultedMultiCalendars.value.count && fromMount && !props.startDate)
144
+ return assignMonthAndYear(getDate(), fromMount);
145
+ };
146
+
147
+ const shouldAssignMultiSolo = () => {
148
+ if (Array.isArray(modelValue.value) && defaultedRange.value.enabled) {
149
+ return getMonth(modelValue.value[0]) === getMonth(modelValue.value[1] ?? modelValue.value[0]);
150
+ }
151
+ return false;
152
+ };
153
+
154
+ // Assign month and year values per date
155
+ const assignMonthAndYear = (date = new Date(), fromMount = false): void => {
156
+ if (!defaultedMultiCalendars.value.count || !defaultedMultiCalendars.value.static || fromMount) {
157
+ setCalendarMonthYear(0, getMonth(date), getYear(date));
158
+ }
159
+ if (
160
+ defaultedMultiCalendars.value.count &&
161
+ (!defaultedMultiCalendars.value.solo || !modelValue.value || shouldAssignMultiSolo())
162
+ ) {
163
+ for (let i = 1; i < defaultedMultiCalendars.value.count; i++) {
164
+ const prevDate = set(getDate(), { month: month.value(i - 1), year: year.value(i - 1) });
165
+ const nextMonth = add(prevDate, { months: 1 });
166
+ calendars.value[i] = { month: getMonth(nextMonth), year: getYear(nextMonth) };
167
+ }
168
+ }
169
+ };
170
+
171
+ // Assign singe value
172
+ const assignSingleValue = (date: Date, fromMount: boolean): void => {
173
+ assignMonthAndYear(date);
174
+ setTime('hours', getHours(date));
175
+ setTime('minutes', getMinutes(date));
176
+ setTime('seconds', getSeconds(date));
177
+ if (defaultedMultiCalendars.value.count && fromMount) {
178
+ handleNextMonthYear();
179
+ }
180
+ };
181
+
182
+ /**
183
+ * In case of multi-calendars, check if the range can fit within the view
184
+ * If it can, set focus index to the first date in the range, rest will be auto adjusted
185
+ * In case of solo multi calendars, always take 0 index as reference
186
+ */
187
+ const getRangeFocusIndex = (dates: Date[]) => {
188
+ if (defaultedMultiCalendars.value.count) {
189
+ if (defaultedMultiCalendars.value.solo) return 0;
190
+ const startMonth = getMonth(dates[0]);
191
+ const endMonth = getMonth(dates[1]);
192
+ const showInTheSameView = Math.abs(endMonth - startMonth) < defaultedMultiCalendars.value.count;
193
+ return showInTheSameView ? 0 : 1;
194
+ }
195
+ return 1;
196
+ };
197
+ // Assign range values
198
+ const assignRangeValue = (dates: Date[], fromMount: boolean) => {
199
+ if (dates[1] && defaultedRange.value.showLastInRange) {
200
+ assignMonthAndYear(dates[getRangeFocusIndex(dates)], fromMount);
201
+ } else {
202
+ assignMonthAndYear(dates[0], fromMount);
203
+ }
204
+ const getValue = (mapper: (date: Date) => number, keys: TimeType): number[] => [
205
+ mapper(dates[0]),
206
+ dates[1] ? mapper(dates[1]) : (time[keys] as number[])[1],
207
+ ];
208
+ setTime('hours', getValue(getHours, 'hours'));
209
+ setTime('minutes', getValue(getMinutes, 'minutes'));
210
+ setTime('seconds', getValue(getSeconds, 'seconds'));
211
+ };
212
+
213
+ // Assign range values, or in case of multiDates, set
214
+ const assignExistingMulti = (dates: Date[], fromMount: boolean) => {
215
+ if ((defaultedRange.value.enabled || props.weekPicker) && !defaultedMultiDates.value.enabled) {
216
+ return assignRangeValue(dates, fromMount);
217
+ }
218
+
219
+ if (defaultedMultiDates.value.enabled && fromMount) {
220
+ const lastEntry = dates[dates.length - 1];
221
+ return assignSingleValue(lastEntry, fromMount);
222
+ }
223
+ };
224
+
225
+ const assignExistingModelValueArr = (fromMount: boolean) => {
226
+ const dates = modelValue.value as Date[];
227
+ assignExistingMulti(dates, fromMount);
228
+ if (defaultedMultiCalendars.value.count && defaultedMultiCalendars.value.solo) {
229
+ handleNextMonthYear();
230
+ }
231
+ };
232
+
233
+ // Handle month change on scroll/arrow/swipe
234
+ const autoChangeMonth = (increment: number, instance: number) => {
235
+ const initialDate = set(getDate(), { month: month.value(instance), year: year.value(instance) });
236
+ const date = increment < 0 ? addMonths(initialDate, 1) : subMonths(initialDate, 1);
237
+ if (validateMonthYearInRange(getMonth(date), getYear(date), increment < 0, props.preventMinMaxNavigation)) {
238
+ setCalendarMonthYear(instance, getMonth(date), getYear(date));
239
+ emit('update-month-year', { instance, month: getMonth(date), year: getYear(date) });
240
+ if (defaultedMultiCalendars.value.count && !defaultedMultiCalendars.value.solo) {
241
+ autoChangeMultiCalendars(instance);
242
+ }
243
+ triggerCalendarTransition();
244
+ }
245
+ };
246
+
247
+ // In multi calendar mode, when the month/year is changed, sync all calendars
248
+ const autoChangeMultiCalendars = (instance: number): void => {
249
+ for (let i = instance - 1; i >= 0; i--) {
250
+ const date = subMonths(set(getDate(), { month: month.value(i + 1), year: year.value(i + 1) }), 1);
251
+ setCalendarMonthYear(i, getMonth(date), getYear(date));
252
+ }
253
+ for (let i = instance + 1; i <= defaultedMultiCalendars.value.count - 1; i++) {
254
+ const date = addMonths(set(getDate(), { month: month.value(i - 1), year: year.value(i - 1) }), 1);
255
+ setCalendarMonthYear(i, getMonth(date), getYear(date));
256
+ }
257
+ };
258
+
259
+ /**
260
+ * Extracted method to map month and year
261
+ */
262
+ const handleNextMonthYear = (): void => {
263
+ if (Array.isArray(modelValue.value) && modelValue.value.length === 2) {
264
+ const date = getDate(
265
+ getDate(modelValue.value[1] ? modelValue.value[1] : addMonths(modelValue.value[0], 1)),
266
+ );
267
+ const [firstMonth, firstYear] = [getMonth(modelValue.value[0]), getYear(modelValue.value[0])];
268
+ const [secondMonth, secondYear] = [getMonth(modelValue.value[1]), getYear(modelValue.value[1])];
269
+
270
+ if (
271
+ (firstMonth !== secondMonth || (firstMonth === secondMonth && firstYear !== secondYear)) &&
272
+ defaultedMultiCalendars.value.solo
273
+ ) {
274
+ setCalendarMonthYear(1, getMonth(date), getYear(date));
275
+ }
276
+ } else if (modelValue.value && !Array.isArray(modelValue.value)) {
277
+ setCalendarMonthYear(0, getMonth(modelValue.value), getYear(modelValue.value));
278
+ assignMonthAndYear(getDate());
279
+ }
280
+ };
281
+
282
+ const setStartDate = () => {
283
+ if (props.startDate) {
284
+ setCalendarMonthYear(0, getMonth(getDate(props.startDate)), getYear(getDate(props.startDate)));
285
+ if (defaultedMultiCalendars.value.count) {
286
+ autoChangeMultiCalendars(0);
287
+ }
288
+ }
289
+ };
290
+
291
+ // Handle mouse scroll
292
+
293
+ const handleScroll = (event: WheelEvent, instance: number): void => {
294
+ if (props.monthChangeOnScroll) {
295
+ const timeDelta: number = new Date().getTime() - lastScrollTime.value.getTime();
296
+ const scrollDistance = Math.abs(event.deltaY);
297
+ let minPause: number = 500;
298
+ if (scrollDistance > 1) minPause = 100;
299
+ if (scrollDistance > 100) minPause = 0;
300
+ if (timeDelta > minPause) {
301
+ lastScrollTime.value = new Date();
302
+ autoChangeMonth(props.monthChangeOnScroll !== 'inverse' ? -event.deltaY : event.deltaY, instance);
303
+ }
304
+ }
305
+ };
306
+
307
+ // Handle arrow key
308
+ const handleArrow = (arrow: 'left' | 'right', instance: number, vertical = false): void => {
309
+ if (props.monthChangeOnArrows && props.vertical === vertical) {
310
+ handleSwipe(arrow, instance);
311
+ }
312
+ };
313
+
314
+ // Handle touch swipe
315
+ const handleSwipe = (direction: 'left' | 'right', instance: number): void => {
316
+ autoChangeMonth(direction === 'right' ? -1 : 1, instance);
317
+ };
318
+
319
+ // Check if the calendar day has a marker
320
+ const getMarker = (date: UnwrapRef<ICalendarDay>): IMarker | undefined => {
321
+ if (propDates.value.markers) {
322
+ return getMapDate(date.value, propDates.value.markers);
323
+ }
324
+ return undefined;
325
+ };
326
+
327
+ const getSixWeeksMode = (firstWeekday: number, gapToEnd: number) => {
328
+ switch (props.sixWeeks === true ? 'append' : props.sixWeeks) {
329
+ case 'prepend':
330
+ return [true, false];
331
+ case 'center':
332
+ return [firstWeekday == 0, true];
333
+ case 'fair':
334
+ return [firstWeekday == 0 || gapToEnd > firstWeekday, true];
335
+ case 'append':
336
+ return [false, false];
337
+ default:
338
+ return [false, false];
339
+ }
340
+ };
341
+
342
+ const handleSixWeeks = (
343
+ weeks: ICalendarDate[],
344
+ firstDate: Date,
345
+ lastDate: Date,
346
+ weekStart: WeekStartNum,
347
+ ): ICalendarDate[] => {
348
+ if (props.sixWeeks && weeks.length < 6) {
349
+ const diff = 6 - weeks.length;
350
+
351
+ const firstWeekday = (firstDate.getDay() + 7 - weekStart) % 7;
352
+ const lastWeekday = (lastDate.getDay() + 7 - weekStart) % 7;
353
+ const gapToEnd = 6 - lastWeekday;
354
+ const [requiresLeadingWeek, doesAlternate] = getSixWeeksMode(firstWeekday, gapToEnd);
355
+
356
+ for (let i = 1; i <= diff; i++) {
357
+ const addLeadingWeek = doesAlternate ? !!(i % 2) == requiresLeadingWeek : requiresLeadingWeek;
358
+ if (addLeadingWeek) {
359
+ const first = weeks[0].days[0];
360
+ const days = getWeekDays(addDays(first.value, -7), getMonth(firstDate));
361
+ weeks.unshift({ days });
362
+ } else {
363
+ const lastWeek = weeks[weeks.length - 1];
364
+ const last = lastWeek.days[lastWeek.days.length - 1];
365
+ const days = getWeekDays(addDays(last.value, 1), getMonth(firstDate));
366
+ weeks.push({ days });
367
+ }
368
+ }
369
+ }
370
+ return weeks;
371
+ };
372
+ // Get 7 days from the provided start date, month is used to check whether the date is from the specified month or in the offset
373
+ const getWeekDays = (startDay: Date, month: number): ICalendarDay[] => {
374
+ const startDate = getDate(startDay);
375
+ const dates = [];
376
+ for (let i = 0; i < 7; i++) {
377
+ const next = addDays(startDate, i);
378
+ const isNext = getMonth(next) !== month;
379
+ dates.push({
380
+ text: props.hideOffsetDates && isNext ? '' : next.getDate(),
381
+ value: next,
382
+ current: !isNext,
383
+ classData: {},
384
+ });
385
+ }
386
+ return dates;
387
+ };
388
+
389
+ // Get days for the calendar to be displayed in a table grouped by weeks
390
+ const getCalendarDays = (month: number, year: number): ICalendarDate[] => {
391
+ const weeks: ICalendarDate[] = [];
392
+ const firstDate = new Date(year, month);
393
+ const lastDate = new Date(year, month + 1, 0);
394
+
395
+ const weekStartsOn = props.weekStart as WeekStartNum;
396
+
397
+ const firstDateInCalendar = startOfWeek(firstDate, { weekStartsOn });
398
+
399
+ const addDaysToWeek = (date: Date) => {
400
+ const days = getWeekDays(date, month);
401
+ weeks.push({ days });
402
+ if (
403
+ !weeks[weeks.length - 1].days.some((day) =>
404
+ isDateEqual(resetDateTime(day.value), resetDateTime(lastDate)),
405
+ )
406
+ ) {
407
+ const nextDate = addDays(date, 7);
408
+ addDaysToWeek(nextDate);
409
+ }
410
+ };
411
+ addDaysToWeek(firstDateInCalendar);
412
+
413
+ return handleSixWeeks(weeks, firstDate, lastDate, weekStartsOn);
414
+ };
415
+
416
+ // Called on selectDate when the regular single picker is used
417
+ const handleSingleDateSelect = (day: ICalendarDay) => {
418
+ const date = setDateTime(getDate(day.value), time.hours as number, time.minutes as number, getSecondsValue());
419
+ emit('date-update', date);
420
+ if (defaultedMultiDates.value.enabled) {
421
+ handleMultiDatesSelect(date, modelValue, defaultedMultiDates.value.limit);
422
+ } else {
423
+ modelValue.value = date;
424
+ }
425
+ updateFlow();
426
+ nextTick().then(() => {
427
+ autoApply();
428
+ });
429
+ };
430
+
431
+ const includesDisabled = (day: Date) => {
432
+ if (!defaultedRange.value.noDisabledRange) return false;
433
+ const daysBetween = getDaysInBetween(tempRange.value[0], day);
434
+ return daysBetween.some((date) => isDisabled(date));
435
+ };
436
+
437
+ // Before range selecting, ensure that modelValue is properly set
438
+ const presetTempRange = () => {
439
+ tempRange.value = modelValue.value ? (modelValue.value as Date[]).slice() : [];
440
+ if (tempRange.value.length === 2 && !(defaultedRange.value.fixedStart || defaultedRange.value.fixedEnd)) {
441
+ tempRange.value = [];
442
+ }
443
+ };
444
+
445
+ // Handles auto range selecting
446
+ const handleAutoRange = (day: ICalendarDay, isNext: boolean) => {
447
+ const autoRange = [
448
+ getDate(day.value),
449
+ addDays(getDate(day.value), +(defaultedRange.value.autoRange as number)),
450
+ ];
451
+ if (isDateRangeAllowed(autoRange)) {
452
+ if (isNext) {
453
+ handleNextCalendarAutoRange(day.value);
454
+ }
455
+ tempRange.value = autoRange;
456
+ } else {
457
+ emit('invalid-date', day.value);
458
+ }
459
+ };
460
+
461
+ /**
462
+ * When using next calendar on auto range mode, adjust month and year for both calendars
463
+ */
464
+ const handleNextCalendarAutoRange = (date: string | Date) => {
465
+ const monthValue = getMonth(getDate(date));
466
+ const yearValue = getYear(getDate(date));
467
+ setCalendarMonthYear(0, monthValue, yearValue);
468
+ if (defaultedMultiCalendars.value.count > 0) {
469
+ for (let i = 1; i < defaultedMultiCalendars.value.count; i++) {
470
+ const next = getNextMonthYear(
471
+ set(getDate(date), { year: year.value(i - 1), month: month.value(i - 1) }),
472
+ );
473
+ setCalendarMonthYear(i, next.month, next.year);
474
+ }
475
+ }
476
+ };
477
+
478
+ // Handle range with fixed start/end
479
+ const setFixedDateRange = (day: ICalendarDay) => {
480
+ if (
481
+ includesDisabled(day.value) ||
482
+ !checkMinMaxRange(day.value, modelValue.value, defaultedRange.value.fixedStart ? 0 : 1)
483
+ ) {
484
+ return emit('invalid-date', day.value);
485
+ }
486
+ tempRange.value = getRangeWithFixedDate(getDate(day.value), modelValue, emit, defaultedRange);
487
+ };
488
+
489
+ // Called on selectDate when range mode is used
490
+ const handleRangeDatesSelect = (day: ICalendarDay, isNext: boolean) => {
491
+ presetTempRange();
492
+ if (defaultedRange.value.autoRange) return handleAutoRange(day, isNext);
493
+ if (defaultedRange.value.fixedStart || defaultedRange.value.fixedEnd) return setFixedDateRange(day);
494
+ if (!tempRange.value[0]) {
495
+ tempRange.value[0] = getDate(day.value);
496
+ emit('range-start', tempRange.value[0]);
497
+ } else if (checkMinMaxRange(getDate(day.value), modelValue.value) && !includesDisabled(day.value)) {
498
+ if (isDateBefore(getDate(day.value), getDate(tempRange.value[0]))) {
499
+ tempRange.value.unshift(getDate(day.value));
500
+ emit('range-end', tempRange.value[0]);
501
+ } else {
502
+ tempRange.value[1] = getDate(day.value);
503
+ emit('range-end', tempRange.value[1]);
504
+ }
505
+ } else {
506
+ if (props.autoApply) {
507
+ emit('auto-apply-invalid', day.value);
508
+ }
509
+ emit('invalid-date', day.value);
510
+ }
511
+ };
512
+
513
+ // Check if seconds are enabled, and return proper value
514
+ const getSecondsValue = (getFirst = true): number => {
515
+ if (props.enableSeconds) {
516
+ if (Array.isArray(time.seconds)) {
517
+ return getFirst ? time.seconds[0] : time.seconds[1];
518
+ }
519
+ return time.seconds;
520
+ }
521
+ return 0;
522
+ };
523
+
524
+ // Assign time to a temp range item
525
+ const assignTime = (index: number) => {
526
+ tempRange.value[index] = setDateTime(
527
+ tempRange.value[index],
528
+ (time.hours as number[])[index],
529
+ (time.minutes as number[])[index],
530
+ getSecondsValue(index !== 1),
531
+ );
532
+ };
533
+
534
+ const validateRangeAfterTimeSet = () => {
535
+ if (tempRange.value[0] && tempRange.value[1]) {
536
+ if (+tempRange.value?.[0] > +tempRange.value?.[1]) {
537
+ tempRange.value.reverse();
538
+ emit('range-start', tempRange.value[0]);
539
+ emit('range-end', tempRange.value[1]);
540
+ }
541
+ }
542
+ };
543
+
544
+ // After range date is select, ensure that proper times are set and assign to modelValue
545
+ const postRangeSelect = () => {
546
+ if (tempRange.value.length) {
547
+ if (tempRange.value[0] && !tempRange.value[1]) {
548
+ assignTime(0);
549
+ } else {
550
+ assignTime(0);
551
+ assignTime(1);
552
+ updateFlow();
553
+ }
554
+ validateRangeAfterTimeSet();
555
+ modelValue.value = tempRange.value.slice();
556
+
557
+ checkRangeAutoApply(tempRange.value, emit, props.autoApply, props.modelAuto);
558
+ }
559
+ };
560
+
561
+ /**
562
+ * Called when the date in the calendar is clicked
563
+ * Do a necessary formatting and assign value to internal
564
+ */
565
+ const selectDate = (day: ICalendarDay, isNext = false): void => {
566
+ if (isDisabled(day.value) || (!day.current && props.hideOffsetDates)) return emit('invalid-date', day.value);
567
+ clickedDate.value = JSON.parse(JSON.stringify(day));
568
+
569
+ if (!defaultedRange.value.enabled) return handleSingleDateSelect(day);
570
+
571
+ if (isNumberArray(time.hours) && isNumberArray(time.minutes) && !defaultedMultiDates.value.enabled) {
572
+ handleRangeDatesSelect(day, isNext);
573
+ postRangeSelect();
574
+ }
575
+ };
576
+
577
+ // Handles selection of month/year
578
+ const updateMonthYear = (instance: number, val: { month: number; year: number; fromNav?: boolean }): void => {
579
+ setCalendarMonthYear(instance, val.month, val.year, true);
580
+
581
+ if (defaultedMultiCalendars.value.count && !defaultedMultiCalendars.value.solo) {
582
+ autoChangeMultiCalendars(instance);
583
+ }
584
+ emit('update-month-year', { instance, month: val.month, year: val.year });
585
+ triggerCalendarTransition(defaultedMultiCalendars.value.solo ? instance : undefined);
586
+
587
+ const flowActive = props.flow?.length ? props.flow[props.flowStep] : undefined;
588
+ if (!val.fromNav && (flowActive === FlowStep.month || flowActive === FlowStep.year)) {
589
+ updateFlow();
590
+ }
591
+ };
592
+
593
+ // Called when the preset date is clicked
594
+ const presetDate = (value: Date[] | string[] | Date | string, noTz?: boolean): void => {
595
+ setPresetDate({
596
+ value,
597
+ modelValue,
598
+ range: defaultedRange.value.enabled,
599
+ timezone: noTz ? undefined : defaultedTz.value.timezone,
600
+ });
601
+
602
+ selectOnAutoApply();
603
+ if (props.multiCalendars) {
604
+ nextTick().then(() => mapInternalModuleValues(true));
605
+ }
606
+ };
607
+
608
+ // Select current date on now button
609
+ const selectCurrentDate = (): void => {
610
+ const dateInTz = dateToTimezoneSafe(getDate(), defaultedTz.value);
611
+ if (!defaultedRange.value.enabled) {
612
+ modelValue.value = dateInTz;
613
+ } else if (modelValue.value && Array.isArray(modelValue.value) && modelValue.value[0]) {
614
+ modelValue.value = isDateBefore(dateInTz, modelValue.value[0])
615
+ ? [dateInTz, modelValue.value[0]]
616
+ : [modelValue.value[0], dateInTz];
617
+ } else {
618
+ modelValue.value = [dateInTz];
619
+ }
620
+
621
+ selectOnAutoApply();
622
+ };
623
+
624
+ const handleTimeUpdate = () => {
625
+ if (Array.isArray(modelValue.value)) {
626
+ if (defaultedMultiDates.value.enabled) {
627
+ const lastEntry = multiDatesLast();
628
+ modelValue.value[modelValue.value.length - 1] = getSetDateTime(lastEntry as Date);
629
+ } else {
630
+ modelValue.value = modelValue.value.map((date, i) => {
631
+ if (date) return getSetDateTime(date, i);
632
+ return date;
633
+ });
634
+ }
635
+ } else {
636
+ modelValue.value = getSetDateTime(modelValue.value);
637
+ }
638
+ emit('time-update');
639
+ };
640
+
641
+ // Get last date in the multi dates arr
642
+ const multiDatesLast = (): Date | null => {
643
+ if (Array.isArray(modelValue.value) && modelValue.value.length) {
644
+ return modelValue.value[modelValue.value.length - 1];
645
+ }
646
+ return null;
647
+ };
648
+
649
+ const updateTime = (value: number | number[], isHours = true, isSeconds = false) => {
650
+ updateTimeValues(value, isHours, isSeconds, handleTimeUpdate);
651
+ };
652
+
653
+ return {
654
+ calendars,
655
+ modelValue,
656
+ month,
657
+ year,
658
+ time,
659
+ disabledTimesConfig,
660
+ today,
661
+ validateTime,
662
+ getCalendarDays,
663
+ getMarker,
664
+ handleScroll,
665
+ handleSwipe,
666
+ handleArrow,
667
+ selectDate,
668
+ updateMonthYear,
669
+ presetDate,
670
+ selectCurrentDate,
671
+ updateTime,
672
+ assignMonthAndYear,
673
+ };
674
+ };