design-system-next 2.24.2 → 2.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/design-system-next.es.d.ts +152 -114
- package/dist/design-system-next.es.js +10058 -9379
- package/dist/design-system-next.es.js.gz +0 -0
- package/dist/design-system-next.umd.js +12 -12
- package/dist/design-system-next.umd.js.gz +0 -0
- package/dist/main.css +1 -1
- package/dist/main.css.gz +0 -0
- package/package.json +3 -2
- package/src/App.vue +1 -89
- package/src/components/date-picker/date-picker.ts +9 -12
- package/src/components/date-picker/date-picker.vue +1 -1
- package/src/components/date-picker/date-range-picker/date-range-picker.ts +9 -12
- package/src/components/date-picker/date-range-picker/use-date-range-picker.ts +64 -49
- package/src/components/date-picker/month-year-picker/month-year-picker.ts +134 -0
- package/src/components/date-picker/month-year-picker/month-year-picker.vue +233 -0
- package/src/components/date-picker/month-year-picker/use-month-year-picker.ts +603 -0
- package/src/components/date-picker/use-date-picker.ts +88 -147
- package/src/components/list/list-item/list-item.ts +60 -60
- package/src/components/list/list.ts +5 -0
- package/src/components/list/list.vue +2 -0
- package/src/components/list/use-list.ts +36 -3
- package/src/components/radio-grouped/radio-grouped.ts +65 -65
- package/src/components/radio-grouped/use-radio-grouped.ts +62 -62
- package/src/components/select/select-multiple/use-select-multiple.ts +7 -3
- package/src/components/select/use-select.ts +9 -5
- package/src/components/sidepanel/sidepanel.ts +7 -0
- package/src/components/sidepanel/sidepanel.vue +24 -4
- package/src/components/sidepanel/use-sidepanel.ts +4 -0
- package/src/components/table/table-header-dropdown/table-header-dropdown.vue +5 -1
- package/src/components/table/table.vue +14 -0
- package/src/components/table/use-table.ts +1 -2
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
import { ref, toRefs, computed, ComputedRef, SetupContext, onMounted, watch } from 'vue';
|
|
2
|
+
import { useVModel, onClickOutside, useDebounceFn } from '@vueuse/core';
|
|
3
|
+
|
|
4
|
+
import dayjs from 'dayjs';
|
|
5
|
+
|
|
6
|
+
import classNames from 'classnames';
|
|
7
|
+
|
|
8
|
+
import type { MonthYearPickerPropTypes, MonthYearPickerEmitTypes } from './month-year-picker';
|
|
9
|
+
|
|
10
|
+
interface MonthYearPickerClasses {
|
|
11
|
+
labelClasses: string;
|
|
12
|
+
monthYearPickerBaseInputClasses: string;
|
|
13
|
+
monthYearPickerInputClasses: string;
|
|
14
|
+
monthYearPickerInputHelperClasses: string;
|
|
15
|
+
monthsTabItemsBaseClasses: string;
|
|
16
|
+
yearsTabItemsBaseClasses: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface MonthsList {
|
|
20
|
+
text: string;
|
|
21
|
+
fullText: string;
|
|
22
|
+
monthValue: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const useMonthYearPicker = (
|
|
26
|
+
props: MonthYearPickerPropTypes,
|
|
27
|
+
emit: SetupContext<MonthYearPickerEmitTypes>['emit'],
|
|
28
|
+
) => {
|
|
29
|
+
const { active, disabled, readonly, error, currentYear, minMaxYear, format } = toRefs(props);
|
|
30
|
+
|
|
31
|
+
const modelValue = useVModel(props, 'modelValue', emit);
|
|
32
|
+
|
|
33
|
+
const monthYearPickerClasses: ComputedRef<MonthYearPickerClasses> = computed(() => {
|
|
34
|
+
const labelClasses = classNames('spr-body-sm-regular spr-text-color-strong spr-block', {
|
|
35
|
+
'spr-text-color-on-fill-disabled': disabled.value,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const monthYearPickerBaseInputClasses = classNames(
|
|
39
|
+
'spr-flex spr-justify-between spr-items-center spr-gap-6 spr-rounded-lg spr-bg-white-50 spr-min-w-[180px] spr-py-1.5 spr-px-3',
|
|
40
|
+
{
|
|
41
|
+
// Normal State
|
|
42
|
+
'spr-border spr-border-solid spr-border-mushroom-200 focus:spr-border-kangkong-700':
|
|
43
|
+
(!error.value && !disabled.value && !active.value && !monthYearPopperState.value) || readonly.value,
|
|
44
|
+
|
|
45
|
+
// Active State
|
|
46
|
+
'spr-border spr-border-solid spr-border-kangkong-700 spr-border-[1.5px] spr-border-solid':
|
|
47
|
+
(active.value || monthYearPopperState.value === true) && !readonly.value,
|
|
48
|
+
|
|
49
|
+
// Error State
|
|
50
|
+
'spr-border spr-border-solid spr-border-tomato-600 focus:spr-border-tomato-600': error.value,
|
|
51
|
+
|
|
52
|
+
// Disabled State
|
|
53
|
+
'spr-background-color-disabled spr-border-white-100 focus:spr-border-white-100 spr-cursor-not-allowed !spr-text-white-400':
|
|
54
|
+
disabled.value,
|
|
55
|
+
|
|
56
|
+
// Readonly State
|
|
57
|
+
'spr-cursor-default': readonly.value,
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const monthYearPickerInputClasses = classNames(
|
|
62
|
+
'spr-h-full spr-border-none spr-bg-transparent spr-outline-none',
|
|
63
|
+
'spr-font-size-200',
|
|
64
|
+
'placeholder:spr-text-color-weak',
|
|
65
|
+
{
|
|
66
|
+
'spr-text-color-strong': !disabled.value && !readonly.value,
|
|
67
|
+
'spr-text-color-on-fill-disabled': disabled.value || readonly.value,
|
|
68
|
+
'spr-cursor-not-allowed': disabled.value,
|
|
69
|
+
},
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const monthYearPickerInputHelperClasses = classNames(
|
|
73
|
+
'spr-body-sm-regular',
|
|
74
|
+
'spr-flex spr-items-center spr-gap-size-spacing-5xs',
|
|
75
|
+
'spr-mt-size-spacing-4xs',
|
|
76
|
+
{
|
|
77
|
+
'spr-text-color-danger-base': error.value,
|
|
78
|
+
'spr-text-color-supporting': !error.value,
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const monthsTabItemsBaseClasses = classNames(
|
|
83
|
+
'spr-subheading-xs spr-relative spr-flex spr-cursor-pointer spr-items-center spr-justify-center spr-rounded-lg spr-p-4',
|
|
84
|
+
'spr-border spr-border-solid',
|
|
85
|
+
'spr-transition spr-duration-150 spr-ease-in-out',
|
|
86
|
+
'active:spr-scale-95',
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const yearsTabItemsBaseClasses = classNames(
|
|
90
|
+
'spr-subheading-xs spr-relative spr-flex spr-cursor-pointer spr-items-center spr-justify-center spr-rounded-lg spr-p-4',
|
|
91
|
+
'spr-border spr-border-solid',
|
|
92
|
+
'spr-transition spr-duration-150 spr-ease-in-out',
|
|
93
|
+
'active:spr-scale-95',
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
labelClasses,
|
|
98
|
+
monthYearPickerBaseInputClasses,
|
|
99
|
+
monthYearPickerInputClasses,
|
|
100
|
+
monthYearPickerInputHelperClasses,
|
|
101
|
+
monthsTabItemsBaseClasses,
|
|
102
|
+
yearsTabItemsBaseClasses,
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const monthYearPickerRef = ref<HTMLInputElement | null>(null);
|
|
107
|
+
const monthInputRef = ref<HTMLInputElement | null>(null);
|
|
108
|
+
const yearInputRef = ref<HTMLInputElement | null>(null);
|
|
109
|
+
|
|
110
|
+
const monthYearPopperState = ref<boolean>(false);
|
|
111
|
+
|
|
112
|
+
const currentTab = ref<string>('tab-months');
|
|
113
|
+
|
|
114
|
+
const currentDate = ref(dayjs());
|
|
115
|
+
|
|
116
|
+
const monthsList = ref(
|
|
117
|
+
Array.from({ length: 12 }, (_, i) => ({
|
|
118
|
+
text: dayjs().month(i).format('MMM'),
|
|
119
|
+
fullText: dayjs().month(i).format('MMMM'),
|
|
120
|
+
monthValue: i,
|
|
121
|
+
})),
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const monthInput = ref<string>('');
|
|
125
|
+
const yearInput = ref<string>('');
|
|
126
|
+
|
|
127
|
+
const monthYearPickerErrors = ref<{ title: string; message: string }[]>([]);
|
|
128
|
+
|
|
129
|
+
// #region - Month Tab
|
|
130
|
+
const selectedMonth = ref<number | null>(null);
|
|
131
|
+
|
|
132
|
+
const monthTabHandleSelectedMonth = (month: { text: string; fullText: string; monthValue: number }) => {
|
|
133
|
+
const monthValue = month.monthValue + 1;
|
|
134
|
+
const formattedMonth = monthValue < 10 ? `0${monthValue}` : `${monthValue}`;
|
|
135
|
+
|
|
136
|
+
monthInput.value = formattedMonth;
|
|
137
|
+
selectedMonth.value = month.monthValue;
|
|
138
|
+
|
|
139
|
+
handleConvertMonthIfValid();
|
|
140
|
+
emitDateFormats();
|
|
141
|
+
emitPartialInputValue();
|
|
142
|
+
|
|
143
|
+
monthYearPickerErrors.value = [];
|
|
144
|
+
|
|
145
|
+
// If both month and year are selected, close the popper
|
|
146
|
+
if (yearInput.value) {
|
|
147
|
+
setTimeout(() => {
|
|
148
|
+
monthYearPopperState.value = false;
|
|
149
|
+
}, 100);
|
|
150
|
+
} else {
|
|
151
|
+
// Switch to year tab if year is not selected
|
|
152
|
+
currentTab.value = 'tab-years';
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
// #endregion - Month Tab
|
|
156
|
+
|
|
157
|
+
// #region - Year Tab
|
|
158
|
+
const yearTabPageData = ref({
|
|
159
|
+
currentPage: 0,
|
|
160
|
+
itemsPerPage: 12,
|
|
161
|
+
yearsArray: Array.from(
|
|
162
|
+
{ length: minMaxYear.value.max - minMaxYear.value.min + 1 },
|
|
163
|
+
(_, index) => minMaxYear.value.min + index,
|
|
164
|
+
).filter((year) => year <= minMaxYear.value.max && year >= minMaxYear.value.min),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const yearTabCurrentYearPage = computed(() => {
|
|
168
|
+
const start = yearTabPageData.value.currentPage * yearTabPageData.value.itemsPerPage;
|
|
169
|
+
const remainingItems = yearTabPageData.value.yearsArray.slice(start);
|
|
170
|
+
|
|
171
|
+
return remainingItems.length < yearTabPageData.value.itemsPerPage
|
|
172
|
+
? remainingItems
|
|
173
|
+
: yearTabPageData.value.yearsArray.slice(start, start + yearTabPageData.value.itemsPerPage);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const yearsTabSetCurrentPageYear = () => {
|
|
177
|
+
const currentYearValue = Number(yearInput.value) || Number(currentYear.value);
|
|
178
|
+
const currentYearIndex = yearTabPageData.value.yearsArray.indexOf(currentYearValue);
|
|
179
|
+
|
|
180
|
+
if (currentYearIndex !== -1) {
|
|
181
|
+
yearTabPageData.value.currentPage = Math.floor(currentYearIndex / yearTabPageData.value.itemsPerPage);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const yearTabGoToPreviousPage = () => {
|
|
186
|
+
if (yearTabPageData.value.currentPage > 0) {
|
|
187
|
+
yearTabPageData.value.currentPage--;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const yearTabGoToNextPage = () => {
|
|
192
|
+
if (
|
|
193
|
+
(yearTabPageData.value.currentPage + 1) * yearTabPageData.value.itemsPerPage <
|
|
194
|
+
yearTabPageData.value.yearsArray.length
|
|
195
|
+
) {
|
|
196
|
+
yearTabPageData.value.currentPage++;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const yearTabIsPreviousButtonDisabled = computed(() => {
|
|
201
|
+
return yearTabPageData.value.currentPage === 0;
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const yearTabIsNextButtonDisabled = computed(() => {
|
|
205
|
+
return (
|
|
206
|
+
(yearTabPageData.value.currentPage + 1) * yearTabPageData.value.itemsPerPage >=
|
|
207
|
+
yearTabPageData.value.yearsArray.length
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const yearTabHandleSelectedYear = (selectedYear: string) => {
|
|
212
|
+
yearInput.value = selectedYear;
|
|
213
|
+
|
|
214
|
+
handleConvertMonthIfValid();
|
|
215
|
+
emitDateFormats();
|
|
216
|
+
emitPartialInputValue();
|
|
217
|
+
|
|
218
|
+
monthYearPickerErrors.value = [];
|
|
219
|
+
|
|
220
|
+
// If both month and year are selected, close the popper
|
|
221
|
+
if (monthInput.value) {
|
|
222
|
+
setTimeout(() => {
|
|
223
|
+
monthYearPopperState.value = false;
|
|
224
|
+
}, 100);
|
|
225
|
+
} else {
|
|
226
|
+
// Switch to month tab if month is not selected
|
|
227
|
+
currentTab.value = 'tab-months';
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
// #endregion - Year Tab
|
|
231
|
+
|
|
232
|
+
// #region - Helper Methods
|
|
233
|
+
const isMonthYearPickerPopperDisabled = computed(() => disabled.value || readonly.value);
|
|
234
|
+
|
|
235
|
+
const setWarningPropsValue = (type: string) => {
|
|
236
|
+
switch (type) {
|
|
237
|
+
case 'MinMaxYear': {
|
|
238
|
+
const _currentYear = Number(currentYear.value) || new Date().getFullYear();
|
|
239
|
+
const { min, max } = minMaxYear.value;
|
|
240
|
+
|
|
241
|
+
if (min > _currentYear || max < _currentYear) {
|
|
242
|
+
console.error(
|
|
243
|
+
`Error: minMaxYear Props - The current year (${_currentYear}) is outside of the valid range. ` +
|
|
244
|
+
`min: ${min}, max: ${max}.`,
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
default:
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const setModelValue = () => {
|
|
257
|
+
if (modelValue.value) {
|
|
258
|
+
// First try to parse with the specified format, then try default format as fallback
|
|
259
|
+
let formattedDate = dayjs(modelValue.value, format.value);
|
|
260
|
+
|
|
261
|
+
// If the date is not valid with the specified format, try with the default format
|
|
262
|
+
if (!formattedDate.isValid()) {
|
|
263
|
+
formattedDate = dayjs(modelValue.value, 'MM-YYYY');
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// If still not valid, try other common formats
|
|
267
|
+
if (!formattedDate.isValid()) {
|
|
268
|
+
const commonFormats = ['YYYY-MM', 'MMMM YYYY', 'MMM YYYY'];
|
|
269
|
+
for (const fmt of commonFormats) {
|
|
270
|
+
const tempDate = dayjs(modelValue.value, fmt);
|
|
271
|
+
if (tempDate.isValid()) {
|
|
272
|
+
formattedDate = tempDate;
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (formattedDate.isValid()) {
|
|
279
|
+
const month = formattedDate.format('MM');
|
|
280
|
+
const year = formattedDate.format('YYYY');
|
|
281
|
+
|
|
282
|
+
handleValidateDate();
|
|
283
|
+
|
|
284
|
+
monthInput.value = month;
|
|
285
|
+
yearInput.value = year;
|
|
286
|
+
selectedMonth.value = formattedDate.month();
|
|
287
|
+
|
|
288
|
+
// Apply the specified format for the model value
|
|
289
|
+
modelValue.value = formattedDate.format(format.value);
|
|
290
|
+
|
|
291
|
+
handleConvertMonthIfValid();
|
|
292
|
+
emitDateFormats();
|
|
293
|
+
|
|
294
|
+
// Use the specified format for the input value
|
|
295
|
+
if (!monthInput.value && !yearInput.value) {
|
|
296
|
+
emit('getInputValue', null);
|
|
297
|
+
} else {
|
|
298
|
+
emit('getInputValue', formattedDate.format(format.value));
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
console.error(`Error: Could not parse date "${modelValue.value}" with format "${format.value}"`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const getMonthObject = (field: string, value: string | number) => {
|
|
307
|
+
return monthsList.value.find(
|
|
308
|
+
(_month: MonthsList) =>
|
|
309
|
+
_month[field as keyof MonthsList].toString().toLowerCase() === value.toString().toLowerCase(),
|
|
310
|
+
);
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const getTabClasses = (tab: string) => {
|
|
314
|
+
return classNames('spr-cursor-pointer', {
|
|
315
|
+
'spr-background-color-pressed !spr-shadow-button': currentTab.value === tab,
|
|
316
|
+
});
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
const handleMonthInput = () => {
|
|
320
|
+
monthYearPopperState.value = false;
|
|
321
|
+
|
|
322
|
+
monthInput.value = monthInput.value.replace(/[^A-Za-z0-9\s]/g, '').toLocaleUpperCase();
|
|
323
|
+
|
|
324
|
+
monthYearPickerErrors.value = [];
|
|
325
|
+
|
|
326
|
+
handleConvertMonthIfValid();
|
|
327
|
+
|
|
328
|
+
handleValidateDate();
|
|
329
|
+
|
|
330
|
+
// Emit the partial date value as user types
|
|
331
|
+
emitPartialInputValue();
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const handleYearInput = () => {
|
|
335
|
+
monthYearPopperState.value = false;
|
|
336
|
+
|
|
337
|
+
yearInput.value = yearInput.value.replace(/[^0-9]/g, '');
|
|
338
|
+
|
|
339
|
+
monthYearPickerErrors.value = [];
|
|
340
|
+
|
|
341
|
+
// Emit the partial date value as user types
|
|
342
|
+
emitPartialInputValue();
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
const handleConvertMonthIfValid = () => {
|
|
346
|
+
if (monthInput.value.length >= 2) {
|
|
347
|
+
const isNumeric = !isNaN(Number(monthInput.value)) && !isNaN(parseFloat(monthInput.value));
|
|
348
|
+
|
|
349
|
+
if (isNumeric) {
|
|
350
|
+
const sanitizeMonth = monthInput.value.replace(/\b0(\d)\b/g, '$1');
|
|
351
|
+
const monthNumber = Number(sanitizeMonth);
|
|
352
|
+
|
|
353
|
+
const monthIsValid = monthsList.value.find((_month: MonthsList) => _month.monthValue + 1 === monthNumber);
|
|
354
|
+
|
|
355
|
+
if (monthIsValid) {
|
|
356
|
+
monthInput.value = monthIsValid.text.toUpperCase();
|
|
357
|
+
selectedMonth.value = monthIsValid.monthValue;
|
|
358
|
+
}
|
|
359
|
+
} else {
|
|
360
|
+
const monthIsValid = monthsList.value.find(
|
|
361
|
+
(_month: MonthsList) => _month.text.toLowerCase() === monthInput.value.toLowerCase(),
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
if (monthIsValid) {
|
|
365
|
+
monthInput.value = monthIsValid.text.toUpperCase();
|
|
366
|
+
selectedMonth.value = monthIsValid.monthValue;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
const handleValidateDate = useDebounceFn(() => {
|
|
373
|
+
if (monthInput.value && yearInput.value) {
|
|
374
|
+
const selectedDate = `${monthInput.value}-01-${yearInput.value}`;
|
|
375
|
+
|
|
376
|
+
const isDateValid = dayjs(selectedDate, 'MM-DD-YYYY').isValid();
|
|
377
|
+
const isYearValid =
|
|
378
|
+
Number(yearInput.value) >= minMaxYear.value.min && Number(yearInput.value) <= minMaxYear.value.max;
|
|
379
|
+
|
|
380
|
+
if (isDateValid && isYearValid) {
|
|
381
|
+
monthYearPickerErrors.value = monthYearPickerErrors.value.filter((error) => error.title !== 'Invalid Date');
|
|
382
|
+
|
|
383
|
+
const monthValue = getMonthObject('text', monthInput.value)?.monthValue;
|
|
384
|
+
selectedMonth.value = Number(monthValue);
|
|
385
|
+
|
|
386
|
+
emitDateFormats();
|
|
387
|
+
} else {
|
|
388
|
+
const errorExists = monthYearPickerErrors.value.some((error) => error.title === 'Invalid Date');
|
|
389
|
+
|
|
390
|
+
if (!errorExists) {
|
|
391
|
+
let errorMessage;
|
|
392
|
+
|
|
393
|
+
if (!isYearValid) {
|
|
394
|
+
errorMessage = `Year must be between ${minMaxYear.value.min} and ${minMaxYear.value.max}.`;
|
|
395
|
+
} else {
|
|
396
|
+
errorMessage = `Invalid Date Format. Please use ${format.value}`;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
monthYearPickerErrors.value.push({
|
|
400
|
+
title: 'Invalid Date',
|
|
401
|
+
message: errorMessage,
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
monthYearPopperState.value = false;
|
|
405
|
+
|
|
406
|
+
console.error(`Invalid Date: "${selectedDate}". ${errorMessage}`);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}, 500);
|
|
411
|
+
|
|
412
|
+
const handleTabClick = (tab: string) => {
|
|
413
|
+
if (currentTab.value === tab) {
|
|
414
|
+
// Toggle back to default tab if clicking on current tab
|
|
415
|
+
currentTab.value = 'tab-months';
|
|
416
|
+
} else {
|
|
417
|
+
currentTab.value = tab;
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
const handleBackspace = (inputType: string, event: KeyboardEvent) => {
|
|
422
|
+
if (event && event instanceof KeyboardEvent && event.key === 'Backspace') {
|
|
423
|
+
if (inputType === 'year' && yearInput.value === '') {
|
|
424
|
+
if (monthInputRef.value) monthInputRef.value.focus();
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
const emitPartialInputValue = () => {
|
|
430
|
+
// Convert month to numeric format if it's text
|
|
431
|
+
let emittedMonth = monthInput.value;
|
|
432
|
+
|
|
433
|
+
if (monthInput.value) {
|
|
434
|
+
const isNumeric = !isNaN(Number(monthInput.value)) && !isNaN(parseFloat(monthInput.value));
|
|
435
|
+
|
|
436
|
+
if (!isNumeric) {
|
|
437
|
+
const monthIsValid = monthsList.value.find(
|
|
438
|
+
(_month: MonthsList) => _month.text.toLowerCase() === monthInput.value.toLowerCase(),
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
if (monthIsValid) {
|
|
442
|
+
emittedMonth =
|
|
443
|
+
monthIsValid.monthValue < 10 ? `0${monthIsValid.monthValue + 1}` : `${monthIsValid.monthValue + 1}`;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Build the partial date string with zeros for empty fields
|
|
449
|
+
const partialMonth = emittedMonth || '0';
|
|
450
|
+
const partialYear = yearInput.value || '0';
|
|
451
|
+
|
|
452
|
+
const partialDateString = `${partialMonth}-${partialYear}`;
|
|
453
|
+
|
|
454
|
+
// Emit the partial date string
|
|
455
|
+
emit('getInputValue', partialDateString);
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
const emitDateFormats = () => {
|
|
459
|
+
if (monthInput.value && yearInput.value) {
|
|
460
|
+
const monthIsValid = monthsList.value.find(
|
|
461
|
+
(_month: MonthsList) => _month.text.toLowerCase() === monthInput.value.toLowerCase(),
|
|
462
|
+
);
|
|
463
|
+
const yearIsValid = yearTabPageData.value.yearsArray.find((_year) => _year === Number(yearInput.value));
|
|
464
|
+
|
|
465
|
+
if (monthIsValid && yearIsValid) {
|
|
466
|
+
const _date = dayjs(`${monthInput.value}-01-${yearInput.value}`, 'MM-DD-YYYY');
|
|
467
|
+
|
|
468
|
+
const formats = {
|
|
469
|
+
// Standard month-year formats
|
|
470
|
+
mmyyyy: _date.format('MM-YYYY'),
|
|
471
|
+
yyyymm: _date.format('YYYY-MM'),
|
|
472
|
+
|
|
473
|
+
// Month-year with slashes
|
|
474
|
+
mmyyyyWithSlashes: _date.format('MM/YYYY'),
|
|
475
|
+
yyyymmWithSlashes: _date.format('YYYY/MM'),
|
|
476
|
+
|
|
477
|
+
// Full month name formats
|
|
478
|
+
monthYear: _date.format('MMMM YYYY'),
|
|
479
|
+
monthYearShort: _date.format('MMM YYYY'),
|
|
480
|
+
|
|
481
|
+
// Miscellaneous formats
|
|
482
|
+
mm: _date.format('MM'),
|
|
483
|
+
yyyy: _date.format('YYYY'),
|
|
484
|
+
mmmm: _date.format('MMMM'),
|
|
485
|
+
mmm: _date.format('MMM'),
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
emit('getDateFormats', formats);
|
|
489
|
+
|
|
490
|
+
// Update the model value with the formatted date using the specified format
|
|
491
|
+
modelValue.value = _date.format(format.value);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
const emitMonthList = () => {
|
|
497
|
+
emit('getMonthList', monthsList.value);
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
const emitYearList = () => {
|
|
501
|
+
emit('getYearList', yearTabPageData.value.yearsArray);
|
|
502
|
+
};
|
|
503
|
+
// #endregion - Helper Methods
|
|
504
|
+
|
|
505
|
+
const clearMonthYear = () => {
|
|
506
|
+
monthInput.value = '';
|
|
507
|
+
yearInput.value = '';
|
|
508
|
+
selectedMonth.value = null;
|
|
509
|
+
modelValue.value = '';
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
const handleSlotClick = () => {
|
|
513
|
+
if (disabled.value || readonly.value) return;
|
|
514
|
+
monthYearPopperState.value = true;
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
watch(monthYearPopperState, (newValue) => {
|
|
518
|
+
if (newValue === false) {
|
|
519
|
+
setTimeout(() => {
|
|
520
|
+
currentTab.value = 'tab-months';
|
|
521
|
+
yearsTabSetCurrentPageYear();
|
|
522
|
+
}, 500);
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
watch(yearInput, (newValue) => {
|
|
527
|
+
if (newValue) {
|
|
528
|
+
const yearNumber = parseInt(newValue, 10);
|
|
529
|
+
|
|
530
|
+
if (isNaN(yearNumber)) return;
|
|
531
|
+
|
|
532
|
+
const yearIndex = yearTabPageData.value.yearsArray.indexOf(yearNumber);
|
|
533
|
+
|
|
534
|
+
if (yearIndex !== -1) {
|
|
535
|
+
const page = Math.floor(yearIndex / yearTabPageData.value.itemsPerPage);
|
|
536
|
+
|
|
537
|
+
yearTabPageData.value.currentPage = page;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
watch(
|
|
543
|
+
minMaxYear,
|
|
544
|
+
() => {
|
|
545
|
+
yearTabPageData.value.yearsArray = Array.from(
|
|
546
|
+
{ length: minMaxYear.value.max - minMaxYear.value.min + 1 },
|
|
547
|
+
(_, index) => minMaxYear.value.min + index,
|
|
548
|
+
).filter((year) => year <= minMaxYear.value.max && year >= minMaxYear.value.min);
|
|
549
|
+
|
|
550
|
+
yearTabPageData.value.currentPage = 0;
|
|
551
|
+
emitYearList();
|
|
552
|
+
},
|
|
553
|
+
{ deep: true },
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
onClickOutside(monthYearPickerRef, () => {
|
|
557
|
+
monthYearPopperState.value = false;
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
onMounted(() => {
|
|
561
|
+
setWarningPropsValue('MinMaxYear');
|
|
562
|
+
|
|
563
|
+
setModelValue();
|
|
564
|
+
yearsTabSetCurrentPageYear();
|
|
565
|
+
emitMonthList();
|
|
566
|
+
emitYearList();
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
watch(modelValue, () => {
|
|
570
|
+
setModelValue();
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
return {
|
|
574
|
+
monthYearPickerClasses,
|
|
575
|
+
monthYearPickerRef,
|
|
576
|
+
monthInputRef,
|
|
577
|
+
yearInputRef,
|
|
578
|
+
monthYearPopperState,
|
|
579
|
+
currentTab,
|
|
580
|
+
currentDate,
|
|
581
|
+
monthsList,
|
|
582
|
+
monthInput,
|
|
583
|
+
yearInput,
|
|
584
|
+
monthYearPickerErrors,
|
|
585
|
+
selectedMonth,
|
|
586
|
+
monthTabHandleSelectedMonth,
|
|
587
|
+
yearTabCurrentYearPage,
|
|
588
|
+
yearTabGoToPreviousPage,
|
|
589
|
+
yearTabGoToNextPage,
|
|
590
|
+
yearTabIsPreviousButtonDisabled,
|
|
591
|
+
yearTabIsNextButtonDisabled,
|
|
592
|
+
yearTabHandleSelectedYear,
|
|
593
|
+
isMonthYearPickerPopperDisabled,
|
|
594
|
+
getMonthObject,
|
|
595
|
+
getTabClasses,
|
|
596
|
+
handleMonthInput,
|
|
597
|
+
handleYearInput,
|
|
598
|
+
handleTabClick,
|
|
599
|
+
handleBackspace,
|
|
600
|
+
clearMonthYear,
|
|
601
|
+
handleSlotClick,
|
|
602
|
+
};
|
|
603
|
+
};
|