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,70 @@
1
+ <template>
2
+ <div>
3
+ <slot v-if="$slots['top-extra']" name="top-extra" :value="internalModelValue" />
4
+ <template v-if="$slots['month-year']">
5
+ <slot
6
+ name="month-year"
7
+ v-bind="{
8
+ years: groupedYears,
9
+ selectYear,
10
+ }"
11
+ />
12
+ </template>
13
+ <template v-else>
14
+ <selection-overlay
15
+ :items="groupedYears"
16
+ :is-last="autoApply && !defaultedConfig.keepActionRow"
17
+ :height="defaultedConfig.modeHeight"
18
+ :config="config"
19
+ :no-overlay-focus="Boolean(noOverlayFocus || textInput)"
20
+ :focus-value="focusYear"
21
+ type="year"
22
+ use-relative
23
+ @selected="selectYear"
24
+ @hover-value="setHoverValue"
25
+ >
26
+ <template v-if="$slots['year-overlay-value']" #item="{ item }">
27
+ <slot name="year-overlay-value" :text="item.text" :value="item.value" />
28
+ </template>
29
+ </selection-overlay>
30
+ </template>
31
+ </div>
32
+ </template>
33
+
34
+ <script lang="ts" setup>
35
+ import SelectionOverlay from '../../components/Common/SelectionOverlay.vue';
36
+
37
+ import { PickerBaseProps } from '../../props';
38
+ import { useYearPicker } from '../../components/YearPicker/year-picker';
39
+ import { useDefaults } from '../../composables';
40
+
41
+ const emit = defineEmits([
42
+ 'update:internal-model-value',
43
+ 'reset-flow',
44
+ 'range-start',
45
+ 'range-end',
46
+ 'auto-apply',
47
+ 'update-month-year',
48
+ ]);
49
+ const props = defineProps({
50
+ ...PickerBaseProps,
51
+ });
52
+
53
+ defineOptions({
54
+ compatConfig: {
55
+ MODE: 3,
56
+ },
57
+ });
58
+
59
+ const { groupedYears, modelValue, focusYear, selectYear, setHoverValue } = useYearPicker(props, emit);
60
+ const { defaultedConfig } = useDefaults(props);
61
+
62
+ const getSidebarProps = () => {
63
+ return {
64
+ modelValue,
65
+ selectYear,
66
+ };
67
+ };
68
+
69
+ defineExpose({ getSidebarProps });
70
+ </script>
@@ -0,0 +1,109 @@
1
+ import { computed, nextTick, onMounted, ref } from 'vue';
2
+ import { getYear, setYear, startOfYear } from 'date-fns';
3
+
4
+ import { useDefaults, useModel } from '../../composables';
5
+ import { checkMinMaxValue, getYears, groupListAndMap } from '../../utils/util';
6
+ import {
7
+ checkHighlightYear,
8
+ getDate,
9
+ getMinMaxYear,
10
+ isDateBetween,
11
+ resetDate,
12
+ resetDateTime,
13
+ } from '../../utils/date-utils';
14
+ import { checkRangeAutoApply, setMonthOrYearRange } from '../../composables/shared';
15
+
16
+ import type { PickerBasePropsType } from '../../props';
17
+ import type { VueEmit, IDefaultSelect } from '../../interfaces';
18
+
19
+ export const useYearPicker = (props: PickerBasePropsType, emit: VueEmit) => {
20
+ const reMap = () => {
21
+ if (props.isTextInputDate) focusYear.value = getYear(getDate(props.startDate));
22
+ };
23
+ const { modelValue } = useModel(props, emit, reMap);
24
+ const hoverDate = ref<Date | null>(null);
25
+ const { defaultedHighlight, defaultedMultiDates, defaultedFilters, defaultedRange, propDates } = useDefaults(props);
26
+ const focusYear = ref();
27
+
28
+ onMounted(() => {
29
+ if (props.startDate) {
30
+ if ((modelValue.value && props.focusStartDate) || !modelValue.value) {
31
+ focusYear.value = getYear(getDate(props.startDate));
32
+ }
33
+ }
34
+ });
35
+
36
+ const isYearActive = (year: number) => {
37
+ if (Array.isArray(modelValue.value)) {
38
+ return modelValue.value.some((date) => getYear(date) === year);
39
+ }
40
+ return modelValue.value ? getYear(modelValue.value) === year : false;
41
+ };
42
+
43
+ const isYearBetween = (year: number) => {
44
+ if (defaultedRange.value.enabled) {
45
+ if (Array.isArray(modelValue.value)) {
46
+ return isDateBetween(modelValue.value, hoverDate.value, yearToDate(year));
47
+ }
48
+ return false;
49
+ }
50
+ return false;
51
+ };
52
+
53
+ const groupedYears = computed(() => {
54
+ return groupListAndMap(getYears(props.yearRange, props.locale, props.reverseYears), (year: IDefaultSelect) => {
55
+ const active = isYearActive(year.value);
56
+ const disabled =
57
+ checkMinMaxValue(
58
+ year.value,
59
+ getMinMaxYear(propDates.value.minDate),
60
+ getMinMaxYear(propDates.value.maxDate),
61
+ ) || defaultedFilters.value.years.includes(year.value);
62
+ const isBetween = isYearBetween(year.value) && !active;
63
+ const highlighted = checkHighlightYear(defaultedHighlight.value, year.value);
64
+ return { active, disabled, isBetween, highlighted };
65
+ });
66
+ });
67
+
68
+ const yearToDate = (year: number): Date => {
69
+ return setYear(resetDate(startOfYear(new Date())), year);
70
+ };
71
+
72
+ const selectYear = (year: number) => {
73
+ emit('update-month-year', { instance: 0, year });
74
+ if (defaultedMultiDates.value.enabled) {
75
+ if (!modelValue.value) {
76
+ modelValue.value = [setYear(resetDateTime(startOfYear(getDate())), year)];
77
+ } else if (Array.isArray(modelValue.value)) {
78
+ const years = modelValue.value?.map((date) => getYear(date));
79
+ if (years.includes(year)) {
80
+ modelValue.value = modelValue.value.filter((date) => getYear(date) !== year);
81
+ } else {
82
+ modelValue.value.push(setYear(resetDateTime(getDate()), year));
83
+ }
84
+ }
85
+ return emit('auto-apply', true);
86
+ }
87
+ if (defaultedRange.value.enabled) {
88
+ modelValue.value = setMonthOrYearRange(modelValue, yearToDate(year), emit);
89
+ nextTick().then(() => {
90
+ checkRangeAutoApply(modelValue.value as Date[], emit, props.autoApply, props.modelAuto);
91
+ });
92
+ } else {
93
+ modelValue.value = yearToDate(year);
94
+ emit('auto-apply');
95
+ }
96
+ };
97
+
98
+ const setHoverValue = (value: number) => {
99
+ hoverDate.value = setYear(resetDate(new Date()), value);
100
+ };
101
+
102
+ return {
103
+ groupedYears,
104
+ modelValue,
105
+ focusYear,
106
+ setHoverValue,
107
+ selectYear,
108
+ };
109
+ };
@@ -0,0 +1,105 @@
1
+ <template>
2
+ <div class="dp--year-mode-picker" :class="{ 'dp--hidden-el': overlayOpen }">
3
+ <ArrowBtn
4
+ v-if="showLeftIcon(defaultedMultiCalendars, instance)"
5
+ ref="mpPrevIconRef"
6
+ :aria-label="defaultedAriaLabels?.prevYear"
7
+ :disabled="isDisabled(false)"
8
+ :class="defaultedUI?.navBtnPrev"
9
+ @activate="handleYear(false)"
10
+ >
11
+ <slot v-if="$slots['arrow-left']" name="arrow-left" />
12
+ <ChevronLeftIcon v-if="!$slots['arrow-left']" />
13
+ </ArrowBtn>
14
+ <button
15
+ ref="mpYearButtonRef"
16
+ class="dp__btn dp--year-select"
17
+ type="button"
18
+ :aria-label="`${year}-${defaultedAriaLabels?.openYearsOverlay}`"
19
+ :data-test="`year-mode-btn-${instance}`"
20
+ @click="() => toggleYearPicker(false)"
21
+ @keydown.enter="() => toggleYearPicker(false)"
22
+ >
23
+ <slot v-if="$slots.year" name="year" :year="year" />
24
+ <template v-if="!$slots.year">{{ year }}</template>
25
+ </button>
26
+ <ArrowBtn
27
+ v-if="showRightIcon(defaultedMultiCalendars, instance)"
28
+ ref="mpNextIconRef"
29
+ :aria-label="defaultedAriaLabels?.nextYear"
30
+ :disabled="isDisabled(true)"
31
+ :class="defaultedUI?.navBtnNext"
32
+ @activate="handleYear(true)"
33
+ >
34
+ <slot v-if="$slots['arrow-right']" name="arrow-right" />
35
+ <ChevronRightIcon v-if="!$slots['arrow-right']" />
36
+ </ArrowBtn>
37
+ </div>
38
+ <transition :name="transitionName(showYearPicker)" :css="showTransition">
39
+ <SelectionOverlay
40
+ v-if="showYearPicker"
41
+ :items="items"
42
+ :text-input="textInput"
43
+ :esc-close="escClose"
44
+ :config="config"
45
+ :is-last="autoApply && !defaultedConfig.keepActionRow"
46
+ :hide-navigation="hideNavigation"
47
+ :aria-labels="ariaLabels"
48
+ :overlay-label="defaultedAriaLabels?.yearPicker?.(true)"
49
+ type="year"
50
+ @toggle="toggleYearPicker"
51
+ @selected="handleYearSelect($event)"
52
+ >
53
+ <template #button-icon>
54
+ <slot v-if="$slots['calendar-icon']" name="calendar-icon" />
55
+ <CalendarIcon v-if="!$slots['calendar-icon']" />
56
+ </template>
57
+ <template v-if="$slots['year-overlay-value']" #item="{ item }">
58
+ <slot name="year-overlay-value" :text="item.text" :value="item.value" />
59
+ </template>
60
+ </SelectionOverlay>
61
+ </transition>
62
+ </template>
63
+
64
+ <script setup lang="ts">
65
+ import SelectionOverlay from '../../components/Common/SelectionOverlay.vue';
66
+ import ArrowBtn from '../../components/Common/ArrowBtn.vue';
67
+ import { CalendarIcon, ChevronLeftIcon, ChevronRightIcon } from '../../components/Icons';
68
+
69
+ import { useCommon, useDefaults, useTransitions } from '../../composables';
70
+ import { PickerBaseProps } from '../../props';
71
+
72
+ import { type PropType, ref } from 'vue';
73
+ import type { OverlayGridItem } from '../../interfaces';
74
+
75
+ const emit = defineEmits(['toggle-year-picker', 'year-select', 'handle-year']);
76
+ const props = defineProps({
77
+ ...PickerBaseProps,
78
+ showYearPicker: { type: Boolean as PropType<boolean>, default: false },
79
+ items: { type: Array as PropType<OverlayGridItem[][]>, default: () => [] },
80
+ instance: { type: Number as PropType<number>, default: 0 },
81
+ year: { type: Number as PropType<number>, default: 0 },
82
+ isDisabled: { type: Function as PropType<(isNext: boolean) => boolean>, default: () => false },
83
+ });
84
+
85
+ const { showRightIcon, showLeftIcon } = useCommon();
86
+ const { defaultedConfig, defaultedMultiCalendars, defaultedAriaLabels, defaultedTransitions, defaultedUI } =
87
+ useDefaults(props);
88
+ const { showTransition, transitionName } = useTransitions(defaultedTransitions);
89
+
90
+ const overlayOpen = ref(false);
91
+
92
+ const toggleYearPicker = (flow = false, show?: boolean) => {
93
+ overlayOpen.value = !overlayOpen.value;
94
+ emit('toggle-year-picker', { flow, show });
95
+ };
96
+
97
+ const handleYearSelect = (year: number) => {
98
+ overlayOpen.value = false;
99
+ emit('year-select', year);
100
+ };
101
+
102
+ const handleYear = (increment = false): void => {
103
+ emit('handle-year', increment);
104
+ };
105
+ </script>
@@ -0,0 +1,199 @@
1
+ import { computed, onMounted, ref, watch } from 'vue';
2
+ import { addYears, differenceInYears, endOfYear, getMonth, getYear, set, startOfYear, subYears } from 'date-fns';
3
+
4
+ import { checkHighlightYear, getDate, getMinMaxYear, resetDate, validateMonthYear } from '../../utils/date-utils';
5
+ import { checkMinMaxValue, getYears, groupListAndMap } from '../../utils/util';
6
+
7
+ import type { ComputedRef, WritableComputedRef, Ref } from 'vue';
8
+ import type {
9
+ InternalModuleValue,
10
+ MultiCalendarsOptions,
11
+ ICalendarData,
12
+ IDefaultSelect,
13
+ OverlayGridItem,
14
+ VueEmit,
15
+ Highlight,
16
+ HighlightFn,
17
+ PropDates,
18
+ DateFilter,
19
+ RangeConfig,
20
+ } from '../../interfaces';
21
+ import type { PickerBasePropsType } from '../../props';
22
+ import { FlowStep } from '../../constants';
23
+
24
+ interface Opts {
25
+ multiCalendars: ComputedRef<MultiCalendarsOptions>;
26
+ calendars: Ref<ICalendarData[]>;
27
+ modelValue: WritableComputedRef<InternalModuleValue>;
28
+ props: PickerBasePropsType;
29
+ year: ComputedRef<(instance: number) => number>;
30
+ month: ComputedRef<(instance: number) => number>;
31
+ highlight: ComputedRef<Highlight | HighlightFn>;
32
+ propDates: ComputedRef<PropDates>;
33
+ filters: ComputedRef<DateFilter>;
34
+ range: ComputedRef<RangeConfig>;
35
+ emit: VueEmit;
36
+ }
37
+
38
+ /**
39
+ * Both modes shared logic
40
+ */
41
+ export const useMonthOrQuarterPicker = ({
42
+ multiCalendars,
43
+ range,
44
+ highlight,
45
+ propDates,
46
+ calendars,
47
+ modelValue,
48
+ props,
49
+ filters,
50
+ year,
51
+ month,
52
+ emit,
53
+ }: Opts) => {
54
+ const years = computed(() => getYears(props.yearRange, props.locale, props.reverseYears));
55
+ const showYearPicker = ref([false]);
56
+
57
+ const isDisabled = computed(() => (instance: number, next: boolean) => {
58
+ const currentDate = set(resetDate(new Date()), {
59
+ month: month.value(instance),
60
+ year: year.value(instance),
61
+ });
62
+ const date = next ? endOfYear(currentDate) : startOfYear(currentDate);
63
+ return validateMonthYear(
64
+ date,
65
+ propDates.value.maxDate,
66
+ propDates.value.minDate,
67
+ props.preventMinMaxNavigation,
68
+ next,
69
+ );
70
+ });
71
+
72
+ const isSoloMultiInRange = () => {
73
+ return Array.isArray(modelValue.value) && multiCalendars.value.solo && modelValue.value[1];
74
+ };
75
+
76
+ const assignMultiCalendars = () => {
77
+ for (let i = 0; i < multiCalendars.value.count; i++) {
78
+ if (i === 0) {
79
+ calendars.value[i] = calendars.value[0];
80
+ } else if (i === multiCalendars.value.count - 1 && isSoloMultiInRange()) {
81
+ calendars.value[i] = {
82
+ month: getMonth((modelValue.value as Date[])[1]),
83
+ year: getYear((modelValue.value as Date[])[1]),
84
+ };
85
+ } else {
86
+ const prevDate = set(getDate(), calendars.value[i - 1]);
87
+ calendars.value[i] = { month: getMonth(prevDate), year: getYear(addYears(prevDate, 1)) };
88
+ }
89
+ }
90
+ };
91
+
92
+ const updateMultiCalendars = (instance: number) => {
93
+ if (!instance) return assignMultiCalendars();
94
+ const date = set(getDate(), calendars.value[instance]);
95
+ calendars.value[0].year = getYear(subYears(date, multiCalendars.value.count - 1));
96
+ return assignMultiCalendars();
97
+ };
98
+
99
+ const getDateToFocus = (dateOne: Date, dateTwo: Date) => {
100
+ const diff = differenceInYears(dateTwo, dateOne);
101
+ return range.value.showLastInRange && diff > 1 ? dateTwo : dateOne;
102
+ };
103
+
104
+ const getRangedValueDate = (dates: Date[]) => {
105
+ if (props.focusStartDate) return dates[0];
106
+ if (multiCalendars.value.solo) return dates[0];
107
+ return dates[1] ? getDateToFocus(dates[0], dates[1]) : dates[0];
108
+ };
109
+
110
+ const checkModelValue = () => {
111
+ if (modelValue.value) {
112
+ const firstDate = Array.isArray(modelValue.value) ? getRangedValueDate(modelValue.value) : modelValue.value;
113
+ calendars.value[0] = { month: getMonth(firstDate), year: getYear(firstDate) };
114
+ }
115
+ };
116
+
117
+ const assign = () => {
118
+ checkModelValue();
119
+ if (multiCalendars.value.count) {
120
+ assignMultiCalendars();
121
+ }
122
+ };
123
+
124
+ watch(modelValue, (newVal, oldVal) => {
125
+ if (props.isTextInputDate) {
126
+ if (JSON.stringify(newVal ?? {}) !== JSON.stringify(oldVal ?? {})) {
127
+ assign();
128
+ }
129
+ }
130
+ });
131
+
132
+ onMounted(() => {
133
+ assign();
134
+ });
135
+
136
+ const selectYear = (year: number, instance: number) => {
137
+ calendars.value[instance].year = year;
138
+ emit('update-month-year', { instance, year, month: calendars.value[instance].month });
139
+ if (multiCalendars.value.count && !multiCalendars.value.solo) {
140
+ updateMultiCalendars(instance);
141
+ }
142
+ };
143
+
144
+ const groupedYears = computed(() => (instance: number): OverlayGridItem[][] => {
145
+ return groupListAndMap(years.value, (y: IDefaultSelect) => {
146
+ const active = year.value(instance) === y.value;
147
+ const disabled =
148
+ checkMinMaxValue(
149
+ y.value,
150
+ getMinMaxYear(propDates.value.minDate),
151
+ getMinMaxYear(propDates.value.maxDate),
152
+ ) || filters.value.years?.includes(year.value(instance));
153
+ const highlighted = checkHighlightYear(highlight.value, y.value);
154
+
155
+ return { active, disabled, highlighted };
156
+ });
157
+ });
158
+
159
+ const handleYearSelect = (year: number, instance: number) => {
160
+ selectYear(year, instance);
161
+ toggleYearPicker(instance);
162
+ };
163
+
164
+ const handleYear = (instance: number, increment = false): void => {
165
+ if (!isDisabled.value(instance, increment)) {
166
+ const yearToSelect = increment ? year.value(instance) + 1 : year.value(instance) - 1;
167
+ selectYear(yearToSelect, instance);
168
+ }
169
+ };
170
+
171
+ const toggleYearPicker = (instance: number, flow = false, show?: boolean): void => {
172
+ if (!flow) {
173
+ emit('reset-flow');
174
+ }
175
+
176
+ if (show !== undefined) {
177
+ showYearPicker.value[instance] = show;
178
+ } else {
179
+ showYearPicker.value[instance] = !showYearPicker.value[instance];
180
+ }
181
+
182
+ if (!showYearPicker.value[instance]) {
183
+ emit('overlay-closed');
184
+ emit('overlay-toggle', { open: false, overlay: FlowStep.year });
185
+ } else {
186
+ emit('overlay-toggle', { open: true, overlay: FlowStep.year });
187
+ }
188
+ };
189
+
190
+ return {
191
+ isDisabled,
192
+ groupedYears,
193
+ showYearPicker,
194
+ selectYear,
195
+ toggleYearPicker,
196
+ handleYearSelect,
197
+ handleYear,
198
+ };
199
+ };
@@ -0,0 +1,191 @@
1
+ import { computed, reactive, ref } from 'vue';
2
+
3
+ type ElRefs = Array<HTMLElement | null>;
4
+
5
+ const refSets = reactive({
6
+ monthYear: [] as ElRefs,
7
+ calendar: [] as ElRefs[],
8
+ time: [] as ElRefs,
9
+ actionRow: [] as ElRefs,
10
+ selectionGrid: [] as ElRefs[],
11
+ timePicker: {
12
+ '0': [] as ElRefs[],
13
+ '1': [] as ElRefs[],
14
+ },
15
+ monthPicker: [] as ElRefs[],
16
+ });
17
+ const timePickerBackRef = ref<HTMLElement | null>(null);
18
+ const isSelectionGrid = ref(false);
19
+ const isTimePicker = ref(false);
20
+ const isMonthPicker = ref(false);
21
+ const isTimePickerMode = ref(false);
22
+
23
+ const selectedIndex = ref(0);
24
+ const activeRow = ref(0);
25
+
26
+ export const useArrowNavigation = () => {
27
+ const matrix = computed((): ElRefs[] => {
28
+ if (isSelectionGrid.value) return [...refSets.selectionGrid, refSets.actionRow].filter((set) => set.length);
29
+ if (isTimePicker.value) {
30
+ return [
31
+ ...refSets.timePicker[0],
32
+ ...refSets.timePicker[1],
33
+ isTimePickerMode.value ? [] : [timePickerBackRef.value],
34
+ refSets.actionRow,
35
+ ].filter((set) => set.length);
36
+ }
37
+ if (isMonthPicker.value) return [...refSets.monthPicker, refSets.actionRow];
38
+ return [refSets.monthYear, ...refSets.calendar, refSets.time, refSets.actionRow].filter((set) => set.length);
39
+ });
40
+
41
+ // Handles left and right arrow
42
+ const handleSelectionIndexX = (increment?: boolean): void => {
43
+ selectedIndex.value = increment ? selectedIndex.value + 1 : selectedIndex.value - 1;
44
+ let el = null;
45
+ if (matrix.value[activeRow.value]) {
46
+ el = matrix.value[activeRow.value][selectedIndex.value];
47
+ }
48
+
49
+ if (!el && matrix.value[activeRow.value + (increment ? 1 : -1)]) {
50
+ activeRow.value = activeRow.value + (increment ? 1 : -1);
51
+ selectedIndex.value = increment ? 0 : matrix.value[activeRow.value].length - 1;
52
+ } else if (!el) {
53
+ selectedIndex.value = increment ? selectedIndex.value - 1 : selectedIndex.value + 1;
54
+ }
55
+ };
56
+
57
+ // Handles up and down arrow
58
+ const handleSelectionIndexY = (increment?: boolean): void => {
59
+ if ((activeRow.value === 0 && !increment) || (activeRow.value === matrix.value.length && increment)) return;
60
+ activeRow.value = increment ? activeRow.value + 1 : activeRow.value - 1;
61
+ const el = matrix.value[activeRow.value];
62
+
63
+ if (!el) {
64
+ activeRow.value = increment ? activeRow.value - 1 : activeRow.value + 1;
65
+ } else if (
66
+ matrix.value[activeRow.value] &&
67
+ !matrix.value[activeRow.value][selectedIndex.value] &&
68
+ selectedIndex.value !== 0
69
+ ) {
70
+ selectedIndex.value = matrix.value[activeRow.value].length - 1;
71
+ }
72
+ };
73
+
74
+ const handleElFocus = (increment: boolean): void => {
75
+ let el = null;
76
+ if (matrix.value[activeRow.value]) {
77
+ el = matrix.value[activeRow.value][selectedIndex.value];
78
+ }
79
+ if (el) {
80
+ el.focus({ preventScroll: !isSelectionGrid.value });
81
+ } else {
82
+ selectedIndex.value = increment ? selectedIndex.value - 1 : selectedIndex.value + 1;
83
+ }
84
+ };
85
+
86
+ const arrowRight = (): void => {
87
+ handleSelectionIndexX(true);
88
+ handleElFocus(true);
89
+ };
90
+
91
+ const arrowLeft = (): void => {
92
+ handleSelectionIndexX(false);
93
+ handleElFocus(false);
94
+ };
95
+
96
+ const arrowUp = (): void => {
97
+ handleSelectionIndexY(false);
98
+ handleElFocus(true);
99
+ };
100
+
101
+ const arrowDown = (): void => {
102
+ handleSelectionIndexY(true);
103
+ handleElFocus(true);
104
+ };
105
+
106
+ /**
107
+ * Add values per page, holds the ref values of the focusable elements
108
+ * Build top to bottom
109
+ */
110
+ const buildMatrix = (elements: Array<HTMLElement | null>, set: 'monthYear' | 'time' | 'actionRow'): void => {
111
+ refSets[set] = elements;
112
+ };
113
+
114
+ const buildMultiLevelMatrix = (
115
+ elements: HTMLElement[][],
116
+ set: 'calendar' | 'selectionGrid' | 'monthPicker',
117
+ ): void => {
118
+ refSets[set] = elements;
119
+ };
120
+
121
+ const resetNavigation = (): void => {
122
+ selectedIndex.value = 0;
123
+ activeRow.value = 0;
124
+ };
125
+
126
+ const setMonthPicker = (value: boolean): void => {
127
+ isMonthPicker.value = value;
128
+ resetNavigation();
129
+ };
130
+
131
+ /**
132
+ * For selection grid, things are handled per grid
133
+ */
134
+ const setSelectionGrid = (value: boolean): void => {
135
+ isSelectionGrid.value = value;
136
+ resetNavigation();
137
+ if (!value) {
138
+ refSets.selectionGrid = [];
139
+ }
140
+ };
141
+
142
+ const setTimePicker = (value: boolean, mode = false) => {
143
+ isTimePicker.value = value;
144
+ isTimePickerMode.value = mode;
145
+ resetNavigation();
146
+ if (!value) {
147
+ refSets.timePicker[0] = [];
148
+ refSets.timePicker[1] = [];
149
+ }
150
+ };
151
+
152
+ const setTimePickerElements = (elements: HTMLElement[][], order: 0 | 1 = 0): void => {
153
+ refSets.timePicker[order] = elements;
154
+ };
155
+
156
+ const setTimePickerBackRef = (el: HTMLElement | null): void => {
157
+ timePickerBackRef.value = el;
158
+ };
159
+
160
+ const clearArrowNav = (): void => {
161
+ refSets.monthYear = [];
162
+ refSets.calendar = [];
163
+ refSets.time = [];
164
+ refSets.actionRow = [];
165
+ refSets.selectionGrid = [];
166
+ refSets.timePicker[0] = [];
167
+ refSets.timePicker[1] = [];
168
+ isSelectionGrid.value = false;
169
+ isTimePicker.value = false;
170
+ isTimePickerMode.value = false;
171
+ isMonthPicker.value = false;
172
+ resetNavigation();
173
+ timePickerBackRef.value = null;
174
+ };
175
+
176
+ return {
177
+ buildMatrix,
178
+ buildMultiLevelMatrix,
179
+ setTimePickerBackRef,
180
+ setSelectionGrid,
181
+ setTimePicker,
182
+ setTimePickerElements,
183
+ arrowRight,
184
+ arrowLeft,
185
+ arrowUp,
186
+ arrowDown,
187
+ clearArrowNav,
188
+ setMonthPicker,
189
+ refSets, // exposed for testing
190
+ };
191
+ };