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.
- package/dist/datePicker/components/ActionRow.vue.d.ts +1051 -0
- package/dist/datePicker/components/Common/ArrowBtn.vue.d.ts +29 -0
- package/dist/datePicker/components/Common/InstanceWrap.vue.d.ts +29 -0
- package/dist/datePicker/components/Common/SelectionOverlay.vue.d.ts +55 -0
- package/dist/datePicker/components/DatePicker/DatePicker.vue.d.ts +1114 -0
- package/dist/datePicker/components/DatePicker/DpCalendar.vue.d.ts +1085 -0
- package/dist/datePicker/components/DatePicker/DpHeader.vue.d.ts +1103 -0
- package/dist/datePicker/components/DatePicker/date-picker.d.ts +35 -0
- package/dist/datePicker/components/DatepickerInput.vue.d.ts +1008 -0
- package/dist/datePicker/components/DatepickerMenu.vue.d.ts +1061 -0
- package/dist/datePicker/components/Icons/CalendarIcon.d.ts +9 -0
- package/dist/datePicker/components/Icons/CancelIcon.d.ts +9 -0
- package/dist/datePicker/components/Icons/ChevronDownIcon.d.ts +9 -0
- package/dist/datePicker/components/Icons/ChevronLeftIcon.d.ts +9 -0
- package/dist/datePicker/components/Icons/ChevronRightIcon.d.ts +9 -0
- package/dist/datePicker/components/Icons/ChevronUpIcon.d.ts +9 -0
- package/dist/datePicker/components/Icons/ClockIcon.d.ts +9 -0
- package/dist/datePicker/components/Icons/index.d.ts +7 -0
- package/dist/datePicker/components/MonthPicker/MonthPicker.vue.d.ts +1071 -0
- package/dist/datePicker/components/MonthPicker/month-picker.d.ts +34 -0
- package/dist/datePicker/components/QuarterPicker/QuarterPicker.vue.d.ts +1043 -0
- package/dist/datePicker/components/QuarterPicker/quarter-picker.d.ts +25 -0
- package/dist/datePicker/components/TimePicker/TimeInput.vue.d.ts +1116 -0
- package/dist/datePicker/components/TimePicker/TimePicker.vue.d.ts +1087 -0
- package/dist/datePicker/components/TimePicker/TimePickerSolo.vue.d.ts +1036 -0
- package/dist/datePicker/components/TimePicker/time-picker-utils.d.ts +15 -0
- package/dist/datePicker/components/TimePicker/time-picker.d.ts +13 -0
- package/dist/datePicker/components/YearPicker/YearPicker.vue.d.ts +1040 -0
- package/dist/datePicker/components/YearPicker/year-picker.d.ts +9 -0
- package/dist/datePicker/components/shared/YearModePicker.vue.d.ts +1075 -0
- package/dist/datePicker/components/shared/month-quarter-picker.d.ts +29 -0
- package/dist/datePicker/composables/arrow-navigate.d.ts +26 -0
- package/dist/datePicker/composables/calendar-class.d.ts +8 -0
- package/dist/datePicker/composables/common.d.ts +6 -0
- package/dist/datePicker/composables/defaults.d.ts +37 -0
- package/dist/datePicker/composables/external-internal-mapper.d.ts +14 -0
- package/dist/datePicker/composables/flow.d.ts +10 -0
- package/dist/datePicker/composables/index.d.ts +14 -0
- package/dist/datePicker/composables/model.d.ts +17 -0
- package/dist/datePicker/composables/month-year.d.ts +10 -0
- package/dist/datePicker/composables/position.d.ts +25 -0
- package/dist/datePicker/composables/shared.d.ts +12 -0
- package/dist/datePicker/composables/slots.d.ts +10 -0
- package/dist/datePicker/composables/state.d.ts +8 -0
- package/dist/datePicker/composables/transition.d.ts +7 -0
- package/dist/datePicker/composables/validation.d.ts +12 -0
- package/dist/datePicker/constants/index.d.ts +43 -0
- package/dist/datePicker/datePicker.vue.d.ts +1006 -0
- package/dist/datePicker/directives/clickOutside.d.ts +2 -0
- package/dist/datePicker/index.vue.d.ts +1012 -0
- package/dist/datePicker/interfaces.d.ts +323 -0
- package/dist/datePicker/props.d.ts +865 -0
- package/dist/datePicker/utils/date-utils.d.ts +45 -0
- package/dist/datePicker/utils/defaults.d.ts +42 -0
- package/dist/datePicker/utils/timezone.d.ts +8 -0
- package/dist/datePicker/utils/type-guard.d.ts +1 -0
- package/dist/datePicker/utils/util.d.ts +57 -0
- package/dist/dialog/index.vue.d.ts +6 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.js +13008 -1250
- package/dist/style.css +1188 -1
- package/dist/tooltip/index.vue.d.ts +2 -2
- package/dist/tooltip/usePopper.d.ts +5 -5
- package/package.json +3 -2
- package/src/datePicker/components/ActionRow.vue +216 -0
- package/src/datePicker/components/Common/ArrowBtn.vue +42 -0
- package/src/datePicker/components/Common/InstanceWrap.vue +28 -0
- package/src/datePicker/components/Common/SelectionOverlay.vue +320 -0
- package/src/datePicker/components/DatePicker/DatePicker.vue +302 -0
- package/src/datePicker/components/DatePicker/DpCalendar.vue +405 -0
- package/src/datePicker/components/DatePicker/DpHeader.vue +332 -0
- package/src/datePicker/components/DatePicker/date-picker.ts +674 -0
- package/src/datePicker/components/DatepickerInput.vue +334 -0
- package/src/datePicker/components/DatepickerMenu.vue +424 -0
- package/src/datePicker/components/Icons/CalendarIcon.ts +40 -0
- package/src/datePicker/components/Icons/CancelIcon.ts +32 -0
- package/src/datePicker/components/Icons/ChevronDownIcon.ts +29 -0
- package/src/datePicker/components/Icons/ChevronLeftIcon.ts +29 -0
- package/src/datePicker/components/Icons/ChevronRightIcon.ts +29 -0
- package/src/datePicker/components/Icons/ChevronUpIcon.ts +29 -0
- package/src/datePicker/components/Icons/ClockIcon.ts +32 -0
- package/src/datePicker/components/Icons/index.ts +8 -0
- package/src/datePicker/components/MonthPicker/MonthPicker.vue +130 -0
- package/src/datePicker/components/MonthPicker/month-picker.ts +232 -0
- package/src/datePicker/components/QuarterPicker/QuarterPicker.vue +111 -0
- package/src/datePicker/components/QuarterPicker/quarter-picker.ts +153 -0
- package/src/datePicker/components/TimePicker/TimeInput.vue +477 -0
- package/src/datePicker/components/TimePicker/TimePicker.vue +265 -0
- package/src/datePicker/components/TimePicker/TimePickerSolo.vue +79 -0
- package/src/datePicker/components/TimePicker/time-picker-utils.ts +179 -0
- package/src/datePicker/components/TimePicker/time-picker.ts +112 -0
- package/src/datePicker/components/YearPicker/YearPicker.vue +70 -0
- package/src/datePicker/components/YearPicker/year-picker.ts +109 -0
- package/src/datePicker/components/shared/YearModePicker.vue +105 -0
- package/src/datePicker/components/shared/month-quarter-picker.ts +199 -0
- package/src/datePicker/composables/arrow-navigate.ts +191 -0
- package/src/datePicker/composables/calendar-class.ts +383 -0
- package/src/datePicker/composables/common.ts +25 -0
- package/src/datePicker/composables/defaults.ts +123 -0
- package/src/datePicker/composables/external-internal-mapper.ts +442 -0
- package/src/datePicker/composables/flow.ts +70 -0
- package/src/datePicker/composables/index.ts +14 -0
- package/src/datePicker/composables/model.ts +89 -0
- package/src/datePicker/composables/month-year.ts +72 -0
- package/src/datePicker/composables/position.ts +297 -0
- package/src/datePicker/composables/shared.ts +98 -0
- package/src/datePicker/composables/slots.ts +84 -0
- package/src/datePicker/composables/state.ts +25 -0
- package/src/datePicker/composables/transition.ts +18 -0
- package/src/datePicker/composables/validation.ts +312 -0
- package/src/datePicker/constants/index.ts +49 -0
- package/src/datePicker/datePicker.vue +554 -0
- package/src/datePicker/directives/clickOutside.ts +79 -0
- package/src/datePicker/index.vue +158 -0
- package/src/datePicker/interfaces.ts +404 -0
- package/src/datePicker/props.ts +173 -0
- package/src/datePicker/style/components/_ActionRow.scss +73 -0
- package/src/datePicker/style/components/_Calendar.scss +284 -0
- package/src/datePicker/style/components/_DatepickerInput.scss +109 -0
- package/src/datePicker/style/components/_DatepickerMenu.scss +213 -0
- package/src/datePicker/style/components/_MonthYearInput.scss +97 -0
- package/src/datePicker/style/components/_QuarterPicker.scss +53 -0
- package/src/datePicker/style/components/_SelectionOverlay.scss +142 -0
- package/src/datePicker/style/components/_TimeInput.scss +181 -0
- package/src/datePicker/style/components/_shared.scss +15 -0
- package/src/datePicker/style/main.scss +259 -0
- package/src/datePicker/utils/date-utils.ts +440 -0
- package/src/datePicker/utils/defaults.ts +327 -0
- package/src/datePicker/utils/timezone.ts +38 -0
- package/src/datePicker/utils/type-guard.ts +3 -0
- package/src/datePicker/utils/util.ts +322 -0
- package/src/dialog/index.vue +9 -0
- package/src/form/index.vue +2 -1
- package/src/index.ts +6 -2
- package/src/slider/index.vue +1 -1
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
import { ref, toRef, watch } from 'vue';
|
|
2
|
+
import { addHours, format, getHours, getMinutes, getMonth, getSeconds, getYear, parse, set, setYear } from 'date-fns';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
checkPartialRangeValue,
|
|
6
|
+
checkRangeEnabled,
|
|
7
|
+
dateToUtc,
|
|
8
|
+
formatDate,
|
|
9
|
+
getDate,
|
|
10
|
+
getWeekFromDate,
|
|
11
|
+
isValidDate,
|
|
12
|
+
setDateMonthOrYear,
|
|
13
|
+
setDateTime,
|
|
14
|
+
} from '../utils/date-utils';
|
|
15
|
+
import { convertType, errors } from '../utils/util';
|
|
16
|
+
import { useDefaults } from '../composables/defaults';
|
|
17
|
+
|
|
18
|
+
import type { ModelValue, VueEmit, TimeModel, MonthModel, ModelTypeConverted } from '../interfaces';
|
|
19
|
+
import type { AllPropsType } from '../props';
|
|
20
|
+
import type { Ref } from 'vue';
|
|
21
|
+
import { getTimezoneOffset, localToTz } from '../utils/timezone';
|
|
22
|
+
import { modelTypePredefined } from '../constants';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Handles values from external to internal and vise versa
|
|
26
|
+
*/
|
|
27
|
+
export const useExternalInternalMapper = (emit: VueEmit, props: AllPropsType, isInputFocused: Ref<boolean>) => {
|
|
28
|
+
const internalModelValue = ref();
|
|
29
|
+
|
|
30
|
+
const { defaultedTextInput, defaultedRange, defaultedTz, defaultedMultiDates, getDefaultPattern } =
|
|
31
|
+
useDefaults(props);
|
|
32
|
+
|
|
33
|
+
const inputValue = ref('');
|
|
34
|
+
const formatRef = toRef(props, 'format');
|
|
35
|
+
const formatLocale = toRef(props, 'formatLocale');
|
|
36
|
+
|
|
37
|
+
watch(
|
|
38
|
+
internalModelValue,
|
|
39
|
+
() => {
|
|
40
|
+
if (typeof props.onInternalModelChange === 'function') {
|
|
41
|
+
emit('internal-model-change', internalModelValue.value, emitModelValue(true));
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{ deep: true },
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
watch(defaultedRange, (newVal, oldVal) => {
|
|
48
|
+
if (newVal.enabled !== oldVal.enabled) {
|
|
49
|
+
internalModelValue.value = null;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
watch(formatRef, () => {
|
|
54
|
+
formatInputValue();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const convertModelToTz = (date: Date) => {
|
|
58
|
+
if (defaultedTz.value.timezone && defaultedTz.value.convertModel) {
|
|
59
|
+
return localToTz(date, defaultedTz.value.timezone);
|
|
60
|
+
}
|
|
61
|
+
return date;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const convertZonedModelToLocal = (date: Date) => {
|
|
65
|
+
if (defaultedTz.value.timezone && defaultedTz.value.convertModel) {
|
|
66
|
+
const offset = getTimezoneOffset(defaultedTz.value.timezone);
|
|
67
|
+
return addHours(date, offset);
|
|
68
|
+
}
|
|
69
|
+
return date;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const formatDateFn = (value: Date | Date[], customPattern?: string, parser = false) => {
|
|
73
|
+
return formatDate(
|
|
74
|
+
value,
|
|
75
|
+
props.format,
|
|
76
|
+
props.formatLocale,
|
|
77
|
+
defaultedTextInput.value.rangeSeparator,
|
|
78
|
+
props.modelAuto,
|
|
79
|
+
customPattern ?? getDefaultPattern(),
|
|
80
|
+
parser,
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const getTimeVal = (date?: Date): TimeModel | ModelTypeConverted | null => {
|
|
85
|
+
if (!date) return null;
|
|
86
|
+
if (props.modelType) return toModelType(date);
|
|
87
|
+
return {
|
|
88
|
+
hours: getHours(date),
|
|
89
|
+
minutes: getMinutes(date),
|
|
90
|
+
seconds: props.enableSeconds ? getSeconds(date) : 0,
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const getMonthVal = (date: Date): MonthModel | ModelTypeConverted => {
|
|
95
|
+
if (props.modelType) return toModelType(date);
|
|
96
|
+
return { month: getMonth(date), year: getYear(date) };
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const mapYearExternalToInternal = (value: number | number[]): Date | Date[] => {
|
|
100
|
+
if (Array.isArray(value)) {
|
|
101
|
+
if (defaultedMultiDates.value.enabled) {
|
|
102
|
+
return value.map((val) => convertCustomModeType(val, setYear(getDate(), val)));
|
|
103
|
+
}
|
|
104
|
+
return checkRangeEnabled(
|
|
105
|
+
() => [
|
|
106
|
+
setYear(getDate(), value[0]),
|
|
107
|
+
value[1] ? setYear(getDate(), value[1]) : checkPartialRangeValue(defaultedRange.value.partialRange),
|
|
108
|
+
],
|
|
109
|
+
defaultedRange.value.enabled,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
return setYear(getDate(), +value);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const convertCustomModeType = (value: unknown, defaultValue: Date): Date => {
|
|
116
|
+
const shouldConvert = (typeof value === 'string' || typeof value === 'number') && props.modelType;
|
|
117
|
+
if (shouldConvert) return parseModelType(value);
|
|
118
|
+
return defaultValue;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const mapTimeExternalToInternal = (value: TimeModel | TimeModel[]): Date | Date[] => {
|
|
122
|
+
// Unlike in other modes, partial range is not supported here, since the time needs to be defined on both time inputs
|
|
123
|
+
if (Array.isArray(value)) {
|
|
124
|
+
return [
|
|
125
|
+
convertCustomModeType(
|
|
126
|
+
value[0],
|
|
127
|
+
setDateTime(null, +value[0].hours, +value[0].minutes, value[0].seconds),
|
|
128
|
+
),
|
|
129
|
+
convertCustomModeType(
|
|
130
|
+
value[1],
|
|
131
|
+
setDateTime(null, +value[1].hours, +value[1].minutes, value[1].seconds),
|
|
132
|
+
),
|
|
133
|
+
];
|
|
134
|
+
}
|
|
135
|
+
return convertCustomModeType(value, setDateTime(null, value.hours, value.minutes, value.seconds));
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const mapMonthExternalToInternal = (value: MonthModel | MonthModel[]): Date | Date[] => {
|
|
139
|
+
const today = set(getDate(), { date: 1 });
|
|
140
|
+
if (Array.isArray(value)) {
|
|
141
|
+
if (defaultedMultiDates.value.enabled) {
|
|
142
|
+
return value.map((val) => convertCustomModeType(val, setDateMonthOrYear(today, +val.month, +val.year)));
|
|
143
|
+
}
|
|
144
|
+
return checkRangeEnabled(
|
|
145
|
+
() => [
|
|
146
|
+
convertCustomModeType(value[0], setDateMonthOrYear(today, +value[0].month, +value[0].year)),
|
|
147
|
+
convertCustomModeType(
|
|
148
|
+
value[1],
|
|
149
|
+
value[1]
|
|
150
|
+
? setDateMonthOrYear(today, +value[1].month, +value[1].year)
|
|
151
|
+
: checkPartialRangeValue(defaultedRange.value.partialRange),
|
|
152
|
+
),
|
|
153
|
+
],
|
|
154
|
+
defaultedRange.value.enabled,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
return convertCustomModeType(value, setDateMonthOrYear(today, +value.month, +value.year));
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// Map external multi dates format to internal model value
|
|
161
|
+
const mapMultiDateExternalToInternal = (value: Date[] | string[]) => {
|
|
162
|
+
if (Array.isArray(value)) {
|
|
163
|
+
return value.map((date) => parseModelType(date));
|
|
164
|
+
}
|
|
165
|
+
throw new Error(errors.dateArr('multi-dates'));
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
// Map external week picker format to internal model value
|
|
169
|
+
const mapWeekExternalToInternal = (value: Date[]) => {
|
|
170
|
+
if (Array.isArray(value) && defaultedRange.value.enabled) {
|
|
171
|
+
const startWeek = value[0];
|
|
172
|
+
const endWeek = value[1];
|
|
173
|
+
return [
|
|
174
|
+
getDate(Array.isArray(startWeek) ? startWeek[0] : null),
|
|
175
|
+
getDate(Array.isArray(endWeek) ? endWeek[0] : null),
|
|
176
|
+
];
|
|
177
|
+
}
|
|
178
|
+
return getDate(value[0]);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// Map external format to internal model value for range and single picker
|
|
182
|
+
const mapDateExternalToInternal = (value: Date | Date[]) => {
|
|
183
|
+
if (props.modelAuto) {
|
|
184
|
+
if (Array.isArray(value)) return [parseModelType(value[0]), parseModelType(value[1])];
|
|
185
|
+
// In case of auto-apply, if we add null, it will never select range
|
|
186
|
+
return props.autoApply ? [parseModelType(value)] : [parseModelType(value), null];
|
|
187
|
+
}
|
|
188
|
+
if (Array.isArray(value)) {
|
|
189
|
+
return checkRangeEnabled(
|
|
190
|
+
() =>
|
|
191
|
+
value[1]
|
|
192
|
+
? [
|
|
193
|
+
parseModelType(value[0]),
|
|
194
|
+
value[1]
|
|
195
|
+
? parseModelType(value[1])
|
|
196
|
+
: checkPartialRangeValue(defaultedRange.value.partialRange),
|
|
197
|
+
]
|
|
198
|
+
: [parseModelType(value[0])],
|
|
199
|
+
defaultedRange.value.enabled,
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
return parseModelType(value);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* When emitting value back to host, if partial date is enabled and second value is not selected
|
|
207
|
+
* auto add 'null' value as second value
|
|
208
|
+
*/
|
|
209
|
+
const sanitizeModelValue = () => {
|
|
210
|
+
if (
|
|
211
|
+
Array.isArray(internalModelValue.value) &&
|
|
212
|
+
defaultedRange.value.enabled &&
|
|
213
|
+
internalModelValue.value.length === 1
|
|
214
|
+
) {
|
|
215
|
+
internalModelValue.value.push(checkPartialRangeValue(defaultedRange.value.partialRange));
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// Shared method, create mapped array of dates to emit
|
|
220
|
+
const getRangeEmitValue = (): Date[] => {
|
|
221
|
+
const modelValue = internalModelValue.value as Date[];
|
|
222
|
+
return [
|
|
223
|
+
toModelType(modelValue[0]),
|
|
224
|
+
modelValue[1] ? toModelType(modelValue[1]) : checkPartialRangeValue(defaultedRange.value.partialRange),
|
|
225
|
+
] as Date[];
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// Get value for model-auto, single or array, internally it is always handled as an array
|
|
229
|
+
const getModelAutoForExternal = () =>
|
|
230
|
+
(internalModelValue.value as Date[])[1]
|
|
231
|
+
? getRangeEmitValue()
|
|
232
|
+
: toModelType(convertType(internalModelValue.value[0]));
|
|
233
|
+
|
|
234
|
+
// Map internal value for external
|
|
235
|
+
const getMultiDatesForExternal = () =>
|
|
236
|
+
((internalModelValue.value as Date[]) || []).map((date) => toModelType(date) as string);
|
|
237
|
+
|
|
238
|
+
// Parent internal to external function mapper that will return proper date format based on provided config
|
|
239
|
+
const mapInternalDatesToExternal = (noSanitize: boolean = false) => {
|
|
240
|
+
if (!noSanitize) {
|
|
241
|
+
sanitizeModelValue();
|
|
242
|
+
}
|
|
243
|
+
if (props.modelAuto) return getModelAutoForExternal();
|
|
244
|
+
if (defaultedMultiDates.value.enabled) return getMultiDatesForExternal();
|
|
245
|
+
if (Array.isArray(internalModelValue.value)) {
|
|
246
|
+
return checkRangeEnabled(() => getRangeEmitValue(), defaultedRange.value.enabled);
|
|
247
|
+
}
|
|
248
|
+
return toModelType(convertType(internalModelValue.value));
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const mapExternalToInternal = (value: ModelValue) => {
|
|
252
|
+
if (!value || (Array.isArray(value) && !value.length)) return null;
|
|
253
|
+
if (props.timePicker) return mapTimeExternalToInternal(convertType(value));
|
|
254
|
+
if (props.monthPicker) return mapMonthExternalToInternal(convertType(value));
|
|
255
|
+
if (props.yearPicker) return mapYearExternalToInternal(convertType(value));
|
|
256
|
+
if (defaultedMultiDates.value.enabled) return mapMultiDateExternalToInternal(convertType(value));
|
|
257
|
+
if (props.weekPicker) return mapWeekExternalToInternal(convertType(value));
|
|
258
|
+
return mapDateExternalToInternal(convertType(value));
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Map external values to dates that will be used internally by the datepicker
|
|
263
|
+
* Also does the validation of the provided value, if invalid it will use null as a default or an empty value
|
|
264
|
+
*/
|
|
265
|
+
const parseExternalModelValue = (value: ModelValue): void => {
|
|
266
|
+
const mappedDate = mapExternalToInternal(value);
|
|
267
|
+
if (isValidDate(convertType(mappedDate))) {
|
|
268
|
+
internalModelValue.value = convertType(mappedDate);
|
|
269
|
+
formatInputValue();
|
|
270
|
+
} else {
|
|
271
|
+
internalModelValue.value = null;
|
|
272
|
+
inputValue.value = '';
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const formatRangeTextInput = () => {
|
|
277
|
+
const formatter = (value: Date) => format(value, defaultedTextInput.value.format as string);
|
|
278
|
+
return `${formatter(internalModelValue.value[0])} ${defaultedTextInput.value.rangeSeparator} ${
|
|
279
|
+
internalModelValue.value[1] ? formatter(internalModelValue.value[1]) : ''
|
|
280
|
+
}`;
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// If text input format is enabled, on input focus, set the text to the given format
|
|
284
|
+
const formatForTextInput = () => {
|
|
285
|
+
if (isInputFocused.value && internalModelValue.value) {
|
|
286
|
+
if (Array.isArray(internalModelValue.value)) return formatRangeTextInput();
|
|
287
|
+
return format(internalModelValue.value, defaultedTextInput.value.format as string);
|
|
288
|
+
}
|
|
289
|
+
return formatDateFn(internalModelValue.value);
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
// Get proper input value depending on the mode
|
|
293
|
+
const getInputValue = (): string => {
|
|
294
|
+
if (!internalModelValue.value) return '';
|
|
295
|
+
if (defaultedMultiDates.value.enabled)
|
|
296
|
+
return (internalModelValue.value as Date[]).map((date) => formatDateFn(date)).join('; ');
|
|
297
|
+
if (defaultedTextInput.value.enabled && typeof defaultedTextInput.value.format === 'string')
|
|
298
|
+
return formatForTextInput();
|
|
299
|
+
return formatDateFn(internalModelValue.value);
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Map the date value(s) to the human-readable text for the input field
|
|
304
|
+
*/
|
|
305
|
+
const formatInputValue = (): void => {
|
|
306
|
+
if (
|
|
307
|
+
!props.format ||
|
|
308
|
+
typeof props.format === 'string' ||
|
|
309
|
+
(defaultedTextInput.value.enabled && typeof defaultedTextInput.value.format === 'string')
|
|
310
|
+
) {
|
|
311
|
+
inputValue.value = getInputValue();
|
|
312
|
+
} else {
|
|
313
|
+
inputValue.value = props.format(internalModelValue.value);
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
const parseModelType = (value: string | number | Date): Date => {
|
|
318
|
+
if (props.utc) {
|
|
319
|
+
const toDate = new Date(value);
|
|
320
|
+
return props.utc === 'preserve' ? new Date(toDate.getTime() + toDate.getTimezoneOffset() * 60000) : toDate;
|
|
321
|
+
}
|
|
322
|
+
if (props.modelType) {
|
|
323
|
+
if (modelTypePredefined.includes(props.modelType)) return convertModelToTz(new Date(value));
|
|
324
|
+
|
|
325
|
+
if (props.modelType === 'format' && (typeof props.format === 'string' || !props.format))
|
|
326
|
+
return convertModelToTz(
|
|
327
|
+
parse(value as string, getDefaultPattern(), new Date(), { locale: formatLocale.value }),
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
return convertModelToTz(
|
|
331
|
+
parse(value as string, props.modelType, new Date(), { locale: formatLocale.value }),
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return convertModelToTz(new Date(value));
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
const toModelType = (val: Date): string | number | Date => {
|
|
339
|
+
if (!val) return '';
|
|
340
|
+
if (props.utc) {
|
|
341
|
+
return dateToUtc(val, props.utc === 'preserve', props.enableSeconds);
|
|
342
|
+
}
|
|
343
|
+
if (props.modelType) {
|
|
344
|
+
if (props.modelType === 'timestamp') return +convertZonedModelToLocal(val);
|
|
345
|
+
if (props.modelType === 'iso') return convertZonedModelToLocal(val).toISOString();
|
|
346
|
+
|
|
347
|
+
if (props.modelType === 'format' && (typeof props.format === 'string' || !props.format))
|
|
348
|
+
return formatDateFn(convertZonedModelToLocal(val));
|
|
349
|
+
|
|
350
|
+
return formatDateFn(convertZonedModelToLocal(val), props.modelType, true);
|
|
351
|
+
}
|
|
352
|
+
return convertZonedModelToLocal(val);
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
const emitValue = (value: ModelValue, useTz = false, returnOnly = false) => {
|
|
356
|
+
if (returnOnly) return value;
|
|
357
|
+
emit('update:model-value', value);
|
|
358
|
+
if (defaultedTz.value.emitTimezone && useTz) {
|
|
359
|
+
const zonedValue = Array.isArray(value)
|
|
360
|
+
? value.map((date) => localToTz(convertType(date), defaultedTz.value.emitTimezone))
|
|
361
|
+
: localToTz(convertType(value), defaultedTz.value.emitTimezone);
|
|
362
|
+
emit('update:model-timezone-value', zonedValue);
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Shared code between modes that support range and partial range
|
|
368
|
+
* Maps the internal model-value into appropriate output
|
|
369
|
+
*/
|
|
370
|
+
const mapInternalToSpecificExternal = <T extends (val: Date) => ReturnType<T> | ReturnType<T>[]>(mapper: T) => {
|
|
371
|
+
if (Array.isArray(internalModelValue.value)) {
|
|
372
|
+
if (defaultedMultiDates.value.enabled) {
|
|
373
|
+
return internalModelValue.value.map((value) => mapper(value));
|
|
374
|
+
}
|
|
375
|
+
return [
|
|
376
|
+
mapper(internalModelValue.value[0]),
|
|
377
|
+
internalModelValue.value[1]
|
|
378
|
+
? mapper(internalModelValue.value[1])
|
|
379
|
+
: checkPartialRangeValue(defaultedRange.value.partialRange),
|
|
380
|
+
];
|
|
381
|
+
}
|
|
382
|
+
return mapper(convertType(internalModelValue.value));
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
const mapInternalWeekPickerToExternal = () => {
|
|
386
|
+
if (Array.isArray(internalModelValue.value)) {
|
|
387
|
+
const startWeek = getWeekFromDate(internalModelValue.value[0], props.weekStart);
|
|
388
|
+
const endWeek = internalModelValue.value[1]
|
|
389
|
+
? getWeekFromDate(internalModelValue.value[1], props.weekStart)
|
|
390
|
+
: [];
|
|
391
|
+
return [startWeek.map((date) => getDate(date)), endWeek.map((date) => getDate(date))];
|
|
392
|
+
}
|
|
393
|
+
return getWeekFromDate(internalModelValue.value, props.weekStart).map((date) => getDate(date));
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
397
|
+
const modeEmitter = (mapper: any, returnOnly: boolean) =>
|
|
398
|
+
emitValue(convertType(mapInternalToSpecificExternal(mapper)), false, returnOnly);
|
|
399
|
+
|
|
400
|
+
const emitWeekPicker = (returnOnly: boolean) => {
|
|
401
|
+
const value = mapInternalWeekPickerToExternal();
|
|
402
|
+
if (returnOnly) return value;
|
|
403
|
+
return emit('update:model-value', mapInternalWeekPickerToExternal());
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* When date is selected, emit event to update modelValue on external,
|
|
408
|
+
* and format input value
|
|
409
|
+
*/
|
|
410
|
+
const emitModelValue = (returnOnly: boolean = false) => {
|
|
411
|
+
if (!returnOnly) {
|
|
412
|
+
formatInputValue();
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (props.monthPicker) return modeEmitter(getMonthVal, returnOnly);
|
|
416
|
+
if (props.timePicker) return modeEmitter(getTimeVal, returnOnly);
|
|
417
|
+
if (props.yearPicker) return modeEmitter(getYear, returnOnly);
|
|
418
|
+
if (props.weekPicker) return emitWeekPicker(returnOnly);
|
|
419
|
+
return emitValue(mapInternalDatesToExternal(returnOnly), true, returnOnly);
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
// Check if there is any selection before emitting value, to prevent null setting
|
|
423
|
+
const checkBeforeEmit = (): boolean => {
|
|
424
|
+
if (internalModelValue.value) {
|
|
425
|
+
if (defaultedRange.value.enabled) {
|
|
426
|
+
if (defaultedRange.value.partialRange) return internalModelValue.value.length >= 1;
|
|
427
|
+
return internalModelValue.value.length === 2;
|
|
428
|
+
}
|
|
429
|
+
return !!internalModelValue.value;
|
|
430
|
+
}
|
|
431
|
+
return false;
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
return {
|
|
435
|
+
inputValue,
|
|
436
|
+
internalModelValue,
|
|
437
|
+
checkBeforeEmit,
|
|
438
|
+
parseExternalModelValue,
|
|
439
|
+
formatInputValue,
|
|
440
|
+
emitModelValue,
|
|
441
|
+
};
|
|
442
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { ref, reactive, computed, nextTick } from 'vue';
|
|
2
|
+
|
|
3
|
+
import { CMP, FlowStep } from '../constants';
|
|
4
|
+
|
|
5
|
+
import type { Ref } from 'vue';
|
|
6
|
+
import type { Flow, VueEmit } from '../interfaces';
|
|
7
|
+
import type { AllPropsType } from '../props';
|
|
8
|
+
|
|
9
|
+
export const useFlow = (props: AllPropsType, emit: VueEmit, dynCmpRef: Ref<any>) => {
|
|
10
|
+
const flowStep = ref(0);
|
|
11
|
+
|
|
12
|
+
const childrenMounted = reactive({
|
|
13
|
+
[CMP.timePicker]: !props.enableTimePicker || props.timePicker || props.monthPicker,
|
|
14
|
+
[CMP.calendar]: false,
|
|
15
|
+
[CMP.header]: false,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const specificMode = computed(() => props.monthPicker || props.timePicker);
|
|
19
|
+
|
|
20
|
+
const childMount = (cmp: unknown): void => {
|
|
21
|
+
if (props.flow?.length) {
|
|
22
|
+
if (!cmp && specificMode.value) return handleFlow();
|
|
23
|
+
childrenMounted[cmp as CMP] = true;
|
|
24
|
+
|
|
25
|
+
if (!Object.keys(childrenMounted).filter((key) => !childrenMounted[key as CMP]).length) {
|
|
26
|
+
handleFlow();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const updateFlowStep = (): void => {
|
|
32
|
+
if (props.flow?.length && flowStep.value !== -1) {
|
|
33
|
+
flowStep.value += 1;
|
|
34
|
+
emit('flow-step', flowStep.value);
|
|
35
|
+
handleFlow();
|
|
36
|
+
}
|
|
37
|
+
if (props.flow?.length === flowStep.value) {
|
|
38
|
+
nextTick().then(() => resetFlow());
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const resetFlow = (): void => {
|
|
43
|
+
flowStep.value = -1;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const handleFlowStep = (step: Flow, fn: string, ...args: Array<boolean | string>) => {
|
|
47
|
+
if (props.flow[flowStep.value] === step) {
|
|
48
|
+
if (dynCmpRef.value) {
|
|
49
|
+
dynCmpRef.value[fn]?.(...args);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const handleFlow = (skipStep = 0): void => {
|
|
55
|
+
if (skipStep) {
|
|
56
|
+
flowStep.value += skipStep;
|
|
57
|
+
}
|
|
58
|
+
handleFlowStep(FlowStep.month, 'toggleMonthPicker', true);
|
|
59
|
+
handleFlowStep(FlowStep.year, 'toggleYearPicker', true);
|
|
60
|
+
handleFlowStep(FlowStep.calendar, 'toggleTimePicker', false, true);
|
|
61
|
+
handleFlowStep(FlowStep.time, 'toggleTimePicker', true, true);
|
|
62
|
+
|
|
63
|
+
const flowValue = props.flow[flowStep.value];
|
|
64
|
+
if (flowValue === FlowStep.hours || flowValue === FlowStep.minutes || flowValue === FlowStep.seconds) {
|
|
65
|
+
handleFlowStep(flowValue, 'toggleTimePicker', true, true, flowValue);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
return { childMount, updateFlowStep, resetFlow, handleFlow, flowStep };
|
|
70
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from './state';
|
|
2
|
+
export * from './arrow-navigate';
|
|
3
|
+
export * from './external-internal-mapper';
|
|
4
|
+
export * from './month-year';
|
|
5
|
+
export * from './position';
|
|
6
|
+
export * from './slots';
|
|
7
|
+
export * from './transition';
|
|
8
|
+
export * from './model';
|
|
9
|
+
export * from './defaults';
|
|
10
|
+
export * from './calendar-class';
|
|
11
|
+
export * from './validation';
|
|
12
|
+
export * from './common';
|
|
13
|
+
export * from './flow';
|
|
14
|
+
export * from './month-year';
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { computed, ref, reactive, watch } from 'vue';
|
|
2
|
+
import { getHours, getMinutes, getMonth, getYear } from 'date-fns';
|
|
3
|
+
|
|
4
|
+
import { getDate } from '../utils/date-utils';
|
|
5
|
+
|
|
6
|
+
import type { ICalendarData, InternalModuleValue, TimeType, VueEmit } from '../interfaces';
|
|
7
|
+
import type { PickerBasePropsType } from '../props';
|
|
8
|
+
import { useDefaults } from '../composables/defaults';
|
|
9
|
+
import { localToTz } from '../utils/timezone';
|
|
10
|
+
|
|
11
|
+
export const useModel = (props: PickerBasePropsType, emit: VueEmit, reMap?: () => void) => {
|
|
12
|
+
const { defaultedRange, defaultedTz } = useDefaults(props);
|
|
13
|
+
|
|
14
|
+
const today = getDate(localToTz(getDate(), defaultedTz.value.timezone));
|
|
15
|
+
const calendars = ref<ICalendarData[]>([{ month: getMonth(today), year: getYear(today) }]);
|
|
16
|
+
|
|
17
|
+
const timeGetter = (type: TimeType) => {
|
|
18
|
+
const fn = {
|
|
19
|
+
hours: getHours(today),
|
|
20
|
+
minutes: getMinutes(today),
|
|
21
|
+
seconds: 0,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
return defaultedRange.value.enabled ? [fn[type], fn[type]] : fn[type];
|
|
25
|
+
};
|
|
26
|
+
// Time values
|
|
27
|
+
const time = reactive({
|
|
28
|
+
hours: timeGetter('hours'),
|
|
29
|
+
minutes: timeGetter('minutes'),
|
|
30
|
+
seconds: timeGetter('seconds'),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
watch(
|
|
34
|
+
defaultedRange,
|
|
35
|
+
(newVal, oldVal) => {
|
|
36
|
+
if (newVal.enabled !== oldVal.enabled) {
|
|
37
|
+
time.hours = timeGetter('hours');
|
|
38
|
+
time.minutes = timeGetter('minutes');
|
|
39
|
+
time.seconds = timeGetter('seconds');
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{ deep: true },
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const modelValue = computed({
|
|
46
|
+
get: (): InternalModuleValue => {
|
|
47
|
+
return props.internalModelValue;
|
|
48
|
+
},
|
|
49
|
+
set: (value: InternalModuleValue): void => {
|
|
50
|
+
if (!props.readonly && !props.disabled) {
|
|
51
|
+
emit('update:internal-model-value', value);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const month = computed(
|
|
57
|
+
() =>
|
|
58
|
+
(instance: number): number =>
|
|
59
|
+
calendars.value[instance] ? calendars.value[instance].month : 0,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// Get year based on the calendar instance
|
|
63
|
+
const year = computed(
|
|
64
|
+
() =>
|
|
65
|
+
(instance: number): number =>
|
|
66
|
+
calendars.value[instance] ? calendars.value[instance].year : 0,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
watch(
|
|
70
|
+
modelValue,
|
|
71
|
+
(newVal, oldVal) => {
|
|
72
|
+
if (reMap) {
|
|
73
|
+
if (JSON.stringify(newVal ?? {}) !== JSON.stringify(oldVal ?? {})) {
|
|
74
|
+
reMap();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{ deep: true },
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
calendars,
|
|
83
|
+
time,
|
|
84
|
+
modelValue,
|
|
85
|
+
month,
|
|
86
|
+
year,
|
|
87
|
+
today,
|
|
88
|
+
};
|
|
89
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { computed } from 'vue';
|
|
2
|
+
import { addMonths, addYears, getMonth, getYear, set, setYear, subMonths, subYears } from 'date-fns';
|
|
3
|
+
|
|
4
|
+
import { useDefaults, useValidation } from '../composables/index';
|
|
5
|
+
import { getDate, validateMonthYear } from '../utils/date-utils';
|
|
6
|
+
|
|
7
|
+
import type { VueEmit } from '../interfaces';
|
|
8
|
+
import type { PickerBasePropsType } from '../props';
|
|
9
|
+
|
|
10
|
+
export const useMonthYearPick = (props: { month: number; year: number } & PickerBasePropsType, emit: VueEmit) => {
|
|
11
|
+
const { defaultedFilters, propDates } = useDefaults(props);
|
|
12
|
+
const { validateMonthYearInRange } = useValidation(props);
|
|
13
|
+
|
|
14
|
+
const recursiveMonthAdjust = (date: Date, increment: boolean): Date => {
|
|
15
|
+
let monthDate = date;
|
|
16
|
+
if (defaultedFilters.value.months.includes(getMonth(monthDate))) {
|
|
17
|
+
monthDate = increment ? addMonths(date, 1) : subMonths(date, 1);
|
|
18
|
+
return recursiveMonthAdjust(monthDate, increment);
|
|
19
|
+
}
|
|
20
|
+
return monthDate;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const recursiveYearAdjust = (date: Date, increment: boolean): Date => {
|
|
24
|
+
let yearDate = date;
|
|
25
|
+
if (defaultedFilters.value.years.includes(getYear(yearDate))) {
|
|
26
|
+
yearDate = increment ? addYears(date, 1) : subYears(date, 1);
|
|
27
|
+
return recursiveYearAdjust(yearDate, increment);
|
|
28
|
+
}
|
|
29
|
+
return yearDate;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const handleMonthYearChange = (isNext: boolean, fromNav = false): void => {
|
|
33
|
+
const initialDate = set(getDate(), { month: props.month, year: props.year });
|
|
34
|
+
let date = isNext ? addMonths(initialDate, 1) : subMonths(initialDate, 1);
|
|
35
|
+
if (props.disableYearSelect) {
|
|
36
|
+
date = setYear(date, props.year);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let month = getMonth(date);
|
|
40
|
+
let year = getYear(date);
|
|
41
|
+
|
|
42
|
+
if (defaultedFilters.value.months.includes(month)) {
|
|
43
|
+
date = recursiveMonthAdjust(date, isNext);
|
|
44
|
+
month = getMonth(date);
|
|
45
|
+
year = getYear(date);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (defaultedFilters.value.years.includes(year)) {
|
|
49
|
+
date = recursiveYearAdjust(date, isNext);
|
|
50
|
+
year = getYear(date);
|
|
51
|
+
}
|
|
52
|
+
if (validateMonthYearInRange(month, year, isNext, props.preventMinMaxNavigation)) {
|
|
53
|
+
updateMonthYear(month, year, fromNav);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const updateMonthYear = (month: number, year: number, fromNav: boolean): void => {
|
|
58
|
+
emit('update-month-year', { month, year, fromNav });
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const isDisabled = computed(() => (next: boolean) => {
|
|
62
|
+
return validateMonthYear(
|
|
63
|
+
set(getDate(), { month: props.month, year: props.year }),
|
|
64
|
+
propDates.value.maxDate,
|
|
65
|
+
propDates.value.minDate,
|
|
66
|
+
props.preventMinMaxNavigation,
|
|
67
|
+
next,
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return { handleMonthYearChange, isDisabled, updateMonthYear };
|
|
72
|
+
};
|