@coreui/vue-pro 5.13.0 → 5.15.0

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 (115) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/components/calendar/CCalendar.js +61 -65
  3. package/dist/cjs/components/calendar/CCalendar.js.map +1 -1
  4. package/dist/cjs/components/calendar/utils.d.ts +53 -2
  5. package/dist/cjs/components/calendar/utils.js +466 -43
  6. package/dist/cjs/components/calendar/utils.js.map +1 -1
  7. package/dist/cjs/components/date-picker/CDatePicker.d.ts +19 -0
  8. package/dist/cjs/components/date-picker/CDatePicker.js +9 -0
  9. package/dist/cjs/components/date-picker/CDatePicker.js.map +1 -1
  10. package/dist/cjs/components/date-range-picker/CDateRangePicker.d.ts +19 -0
  11. package/dist/cjs/components/date-range-picker/CDateRangePicker.js +98 -57
  12. package/dist/cjs/components/date-range-picker/CDateRangePicker.js.map +1 -1
  13. package/dist/cjs/components/date-range-picker/utils.d.ts +0 -9
  14. package/dist/cjs/components/date-range-picker/utils.js +0 -38
  15. package/dist/cjs/components/date-range-picker/utils.js.map +1 -1
  16. package/dist/cjs/components/dropdown/CDropdown.js +22 -13
  17. package/dist/cjs/components/dropdown/CDropdown.js.map +1 -1
  18. package/dist/cjs/components/dropdown/CDropdownToggle.js +7 -1
  19. package/dist/cjs/components/dropdown/CDropdownToggle.js.map +1 -1
  20. package/dist/cjs/components/focus-trap/CFocusTrap.d.ts +108 -0
  21. package/dist/cjs/components/focus-trap/CFocusTrap.js +254 -0
  22. package/dist/cjs/components/focus-trap/CFocusTrap.js.map +1 -0
  23. package/dist/cjs/components/focus-trap/index.d.ts +6 -0
  24. package/dist/cjs/components/focus-trap/index.js +13 -0
  25. package/dist/cjs/components/focus-trap/index.js.map +1 -0
  26. package/dist/cjs/components/focus-trap/utils.d.ts +28 -0
  27. package/dist/cjs/components/focus-trap/utils.js +83 -0
  28. package/dist/cjs/components/focus-trap/utils.js.map +1 -0
  29. package/dist/cjs/components/index.d.ts +1 -0
  30. package/dist/cjs/components/index.js +70 -66
  31. package/dist/cjs/components/index.js.map +1 -1
  32. package/dist/cjs/components/modal/CModal.d.ts +2 -2
  33. package/dist/cjs/components/modal/CModal.js +19 -27
  34. package/dist/cjs/components/modal/CModal.js.map +1 -1
  35. package/dist/cjs/components/modal/CModalHeader.js +4 -2
  36. package/dist/cjs/components/modal/CModalHeader.js.map +1 -1
  37. package/dist/cjs/components/offcanvas/COffcanvas.js +3 -2
  38. package/dist/cjs/components/offcanvas/COffcanvas.js.map +1 -1
  39. package/dist/cjs/components/picker/CPicker.js +3 -2
  40. package/dist/cjs/components/picker/CPicker.js.map +1 -1
  41. package/dist/cjs/components/time-picker/CTimePicker.d.ts +1 -1
  42. package/dist/cjs/components/time-picker/CTimePicker.js +1 -1
  43. package/dist/cjs/components/time-picker/CTimePicker.js.map +1 -1
  44. package/dist/cjs/components/time-picker/utils.d.ts +1 -1
  45. package/dist/cjs/composables/useDebouncedCallback.d.ts +1 -1
  46. package/dist/cjs/composables/useDebouncedCallback.js +1 -1
  47. package/dist/cjs/composables/useDebouncedCallback.js.map +1 -1
  48. package/dist/cjs/index.js +76 -72
  49. package/dist/cjs/index.js.map +1 -1
  50. package/dist/esm/components/calendar/CCalendar.js +61 -65
  51. package/dist/esm/components/calendar/CCalendar.js.map +1 -1
  52. package/dist/esm/components/calendar/utils.d.ts +53 -2
  53. package/dist/esm/components/calendar/utils.js +464 -44
  54. package/dist/esm/components/calendar/utils.js.map +1 -1
  55. package/dist/esm/components/date-picker/CDatePicker.d.ts +19 -0
  56. package/dist/esm/components/date-picker/CDatePicker.js +9 -0
  57. package/dist/esm/components/date-picker/CDatePicker.js.map +1 -1
  58. package/dist/esm/components/date-range-picker/CDateRangePicker.d.ts +19 -0
  59. package/dist/esm/components/date-range-picker/CDateRangePicker.js +98 -57
  60. package/dist/esm/components/date-range-picker/CDateRangePicker.js.map +1 -1
  61. package/dist/esm/components/date-range-picker/utils.d.ts +0 -9
  62. package/dist/esm/components/date-range-picker/utils.js +1 -38
  63. package/dist/esm/components/date-range-picker/utils.js.map +1 -1
  64. package/dist/esm/components/dropdown/CDropdown.js +23 -14
  65. package/dist/esm/components/dropdown/CDropdown.js.map +1 -1
  66. package/dist/esm/components/dropdown/CDropdownToggle.js +7 -1
  67. package/dist/esm/components/dropdown/CDropdownToggle.js.map +1 -1
  68. package/dist/esm/components/focus-trap/CFocusTrap.d.ts +108 -0
  69. package/dist/esm/components/focus-trap/CFocusTrap.js +252 -0
  70. package/dist/esm/components/focus-trap/CFocusTrap.js.map +1 -0
  71. package/dist/esm/components/focus-trap/index.d.ts +6 -0
  72. package/dist/esm/components/focus-trap/index.js +10 -0
  73. package/dist/esm/components/focus-trap/index.js.map +1 -0
  74. package/dist/esm/components/focus-trap/utils.d.ts +28 -0
  75. package/dist/esm/components/focus-trap/utils.js +78 -0
  76. package/dist/esm/components/focus-trap/utils.js.map +1 -0
  77. package/dist/esm/components/index.d.ts +1 -0
  78. package/dist/esm/components/index.js +2 -0
  79. package/dist/esm/components/index.js.map +1 -1
  80. package/dist/esm/components/modal/CModal.d.ts +2 -2
  81. package/dist/esm/components/modal/CModal.js +19 -27
  82. package/dist/esm/components/modal/CModal.js.map +1 -1
  83. package/dist/esm/components/modal/CModalHeader.js +4 -2
  84. package/dist/esm/components/modal/CModalHeader.js.map +1 -1
  85. package/dist/esm/components/offcanvas/COffcanvas.js +3 -2
  86. package/dist/esm/components/offcanvas/COffcanvas.js.map +1 -1
  87. package/dist/esm/components/picker/CPicker.js +3 -2
  88. package/dist/esm/components/picker/CPicker.js.map +1 -1
  89. package/dist/esm/components/time-picker/CTimePicker.d.ts +1 -1
  90. package/dist/esm/components/time-picker/CTimePicker.js +1 -1
  91. package/dist/esm/components/time-picker/CTimePicker.js.map +1 -1
  92. package/dist/esm/components/time-picker/utils.d.ts +1 -1
  93. package/dist/esm/composables/useDebouncedCallback.d.ts +1 -1
  94. package/dist/esm/composables/useDebouncedCallback.js +1 -1
  95. package/dist/esm/composables/useDebouncedCallback.js.map +1 -1
  96. package/dist/esm/index.js +2 -0
  97. package/dist/esm/index.js.map +1 -1
  98. package/package.json +5 -5
  99. package/src/components/calendar/CCalendar.ts +55 -70
  100. package/src/components/calendar/utils.ts +595 -47
  101. package/src/components/date-picker/CDatePicker.ts +9 -0
  102. package/src/components/date-range-picker/CDateRangePicker.ts +144 -82
  103. package/src/components/date-range-picker/utils.ts +0 -58
  104. package/src/components/dropdown/CDropdown.ts +34 -23
  105. package/src/components/dropdown/CDropdownToggle.ts +8 -2
  106. package/src/components/focus-trap/CFocusTrap.ts +303 -0
  107. package/src/components/focus-trap/index.ts +10 -0
  108. package/src/components/focus-trap/utils.ts +90 -0
  109. package/src/components/index.ts +1 -0
  110. package/src/components/modal/CModal.ts +32 -37
  111. package/src/components/modal/CModalHeader.ts +5 -3
  112. package/src/components/offcanvas/COffcanvas.ts +40 -36
  113. package/src/components/picker/CPicker.ts +58 -52
  114. package/src/components/time-picker/CTimePicker.ts +12 -13
  115. package/src/composables/useDebouncedCallback.ts +1 -1
@@ -5,31 +5,421 @@
5
5
  * @param isoWeek - The ISO week string (e.g., "2023W05" or "2023w05").
6
6
  * @returns The Date object for the Monday of the specified week, or null if invalid.
7
7
  */
8
+ /**
9
+ * Helper function to calculate Monday of ISO week 1 for a given year.
10
+ * @param year - The year to calculate for.
11
+ * @returns The Monday of ISO week 1.
12
+ */
13
+ const getMondayOfISOWeek1 = (year) => {
14
+ const jan4 = new Date(year, 0, 4);
15
+ const jan4DayOfWeek = jan4.getDay();
16
+ const daysFromMonday = jan4DayOfWeek === 0 ? 6 : jan4DayOfWeek - 1; // Sunday = 6 days from Monday
17
+ const mondayOfWeek1 = new Date(jan4);
18
+ mondayOfWeek1.setDate(jan4.getDate() - daysFromMonday);
19
+ return mondayOfWeek1;
20
+ };
21
+ /**
22
+ * Helper function to calculate Monday of a specific ISO week.
23
+ * @param year - The year.
24
+ * @param week - The ISO week number.
25
+ * @returns The Monday of the specified ISO week.
26
+ */
27
+ const getMondayOfISOWeek = (year, week) => {
28
+ const mondayOfWeek1 = getMondayOfISOWeek1(year);
29
+ const weekStart = new Date(mondayOfWeek1);
30
+ // prettier-ignore
31
+ weekStart.setDate(mondayOfWeek1.getDate() + ((week - 1) * 7));
32
+ return weekStart;
33
+ };
34
+ /**
35
+ * Helper function to convert a date to a month number for comparison.
36
+ * @param date - The date to convert.
37
+ * @returns A number representing year*12 + month for easy comparison.
38
+ */
39
+ const dateToMonthNumber = (date) => {
40
+ // prettier-ignore
41
+ return (date.getFullYear() * 12) + date.getMonth();
42
+ };
43
+ /**
44
+ * Helper function to check if a value is within min/max range.
45
+ * @param value - The value to check.
46
+ * @param min - Minimum allowed value (null means no minimum).
47
+ * @param max - Maximum allowed value (null means no maximum).
48
+ * @returns True if the value is outside the range, false if within range.
49
+ */
50
+ const isOutsideRange = (value, min, max) => {
51
+ if (min !== null && value < min) {
52
+ return true;
53
+ }
54
+ if (max !== null && value > max) {
55
+ return true;
56
+ }
57
+ return false;
58
+ };
59
+ /**
60
+ * Converts an ISO week string to a Date object representing the Monday of that week.
61
+ * @param isoWeek - The ISO week string (e.g., "2023W05" or "2023w05").
62
+ * @returns The Date object for the Monday of the specified week.
63
+ */
8
64
  const convertIsoWeekToDate = (isoWeek) => {
9
65
  const [year, week] = isoWeek.split(/[Ww]/);
10
- const date = new Date(Number(year), 0, 4); // 4th Jan is always in week 1
11
- date.setDate(date.getDate() - (date.getDay() || 7) + 1 + (Number(week) - 1) * 7);
12
- return date;
66
+ const parsedYear = parseYearSmart(year);
67
+ const parsedWeek = Number.parseInt(week, 10);
68
+ // Create date from ISO week using helper function
69
+ return getMondayOfISOWeek(parsedYear, parsedWeek);
70
+ };
71
+ /**
72
+ * Parses a week string and returns a Date object for the Monday of that week.
73
+ * @param dateString - The week string to parse.
74
+ * @returns The Date object for the Monday of the week, or null if invalid.
75
+ */
76
+ const parseWeekString = (dateString) => {
77
+ const weekPatterns = [
78
+ /^(\d{4})-W(\d{1,2})$/, // 2023-W05, 2023-W5
79
+ /^(\d{4})W(\d{1,2})$/, // 2023W05, 2023W5
80
+ /^(\d{4})\s+W(\d{1,2})$/, // 2023 W05, 2023 W5
81
+ ];
82
+ for (const pattern of weekPatterns) {
83
+ const match = dateString.trim().match(pattern);
84
+ if (match) {
85
+ const parsedYear = parseYearSmart(match[1]);
86
+ const parsedWeek = Number.parseInt(match[2], 10);
87
+ // Create date from ISO week using helper function
88
+ return getMondayOfISOWeek(parsedYear, parsedWeek);
89
+ }
90
+ }
91
+ // Fallback to existing ISO week parsing
92
+ return convertIsoWeekToDate(dateString);
93
+ };
94
+ /**
95
+ * Parses a month string and returns a Date object for the first day of that month.
96
+ * @param dateString - The month string to parse.
97
+ * @returns The Date object for the first day of the month, or null if invalid.
98
+ */
99
+ const parseMonthString = (dateString) => {
100
+ const monthPatterns = [
101
+ /^(\d{2,4})[-/.\s](\d{1,2})$/, // 2023-12, 23-12, 2023/12, 23/12, 2023 12, etc.
102
+ /^(\d{1,2})[-/.\s](\d{2,4})$/, // 12-2023, 12-23, 12/2023, 12/23, 12 2023, etc.
103
+ ];
104
+ for (const pattern of monthPatterns) {
105
+ const match = dateString.trim().match(pattern);
106
+ if (match) {
107
+ const firstGroup = match[1];
108
+ const secondGroup = match[2];
109
+ // Determine which group is year and which is month
110
+ const parsedFirst = Number.parseInt(firstGroup, 10);
111
+ const parsedSecond = Number.parseInt(secondGroup, 10);
112
+ let parsedYear;
113
+ let parsedMonth;
114
+ // Determine which group is year and which is month based on several heuristics
115
+ if (firstGroup.length >= 3 || parsedFirst >= 100) {
116
+ // First group is clearly a year (3+ digits or >= 100)
117
+ parsedYear = parseYearSmart(firstGroup);
118
+ parsedMonth = parsedSecond - 1;
119
+ }
120
+ else if (secondGroup.length >= 3 || parsedSecond >= 100) {
121
+ // Second group is clearly a year (3+ digits or >= 100)
122
+ parsedYear = parseYearSmart(secondGroup);
123
+ parsedMonth = parsedFirst - 1;
124
+ }
125
+ else {
126
+ // Both groups are 1-2 digits, use context clues
127
+ // If second group is a valid month (1-12), treat first as year
128
+ if (parsedSecond >= 1 && parsedSecond <= 12 && (parsedFirst > 12 || parsedFirst < 1)) {
129
+ parsedYear = parseYearSmart(firstGroup);
130
+ parsedMonth = parsedSecond - 1;
131
+ }
132
+ else {
133
+ // Default: treat second group as year
134
+ parsedYear = parseYearSmart(secondGroup);
135
+ parsedMonth = parsedFirst - 1;
136
+ }
137
+ }
138
+ if (parsedMonth >= 0 && parsedMonth <= 11) {
139
+ return new Date(parsedYear, parsedMonth, 1);
140
+ }
141
+ }
142
+ }
143
+ // For month selection, don't use fallback parsing - return null if no pattern matches
144
+ return null;
145
+ };
146
+ /**
147
+ * Parses a year string or number and returns a Date object for January 1st of that year.
148
+ * @param dateString - The year string or number to parse.
149
+ * @returns The Date object for January 1st of the year, or null if invalid.
150
+ */
151
+ const parseYearString = (dateString) => {
152
+ const yearString = String(dateString);
153
+ const yearPattern = /^(\d{2,4})$/;
154
+ const match = yearString.trim().match(yearPattern);
155
+ if (match) {
156
+ const groups = { year: match[1] };
157
+ return createDateFromYear(groups);
158
+ }
159
+ return parseLocalDateString(yearString);
160
+ };
161
+ /**
162
+ * Helper function to generate multiple date format patterns based on locale.
163
+ * @param locale - The locale to use for date format patterns.
164
+ * @param includeTime - Whether to include time in the patterns.
165
+ * @returns Array of date format patterns.
166
+ */
167
+ const generateDatePatterns = (locale, includeTime) => {
168
+ const referenceDate = new Date(2013, 11, 31, 17, 19, 22);
169
+ const patterns = [];
170
+ try {
171
+ // Get the standard locale format
172
+ const standardFormat = includeTime
173
+ ? referenceDate.toLocaleString(locale)
174
+ : referenceDate.toLocaleDateString(locale);
175
+ patterns.push(standardFormat);
176
+ }
177
+ catch {
178
+ // Fallback to default locale if invalid locale provided
179
+ const standardFormat = includeTime
180
+ ? referenceDate.toLocaleString('en-US')
181
+ : referenceDate.toLocaleDateString('en-US');
182
+ patterns.push(standardFormat);
183
+ }
184
+ // Generate common alternative formats by replacing separators
185
+ const separators = ['/', '-', '.', ' '];
186
+ const standardFormat = patterns[0];
187
+ // Detect the original separator
188
+ let originalSeparator = '/'; // default
189
+ if (standardFormat.includes('/')) {
190
+ originalSeparator = '/';
191
+ }
192
+ else if (standardFormat.includes('-')) {
193
+ originalSeparator = '-';
194
+ }
195
+ else if (standardFormat.includes('.')) {
196
+ originalSeparator = '.';
197
+ }
198
+ for (const sep of separators) {
199
+ if (sep !== originalSeparator) {
200
+ // Escape the original separator for regex if it's a special character
201
+ const escapedSeparator = originalSeparator.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw `\$&`);
202
+ const altFormat = standardFormat.replaceAll(new RegExp(escapedSeparator, 'g'), sep);
203
+ patterns.push(altFormat);
204
+ }
205
+ }
206
+ return patterns;
207
+ };
208
+ /**
209
+ * Helper function to build regex pattern for date parsing.
210
+ * @param formatString - The date format string.
211
+ * @param includeTime - Whether to include time patterns.
212
+ * @returns The regex pattern string.
213
+ */
214
+ const buildDateRegexPattern = (formatString, includeTime) => {
215
+ // First escape special regex characters
216
+ // eslint-disable-next-line unicorn/prefer-string-raw
217
+ let regexPattern = formatString.replaceAll(/[.*+?^${}()|[\\]\\]/g, '\\$&');
218
+ // Then replace the date/time components with regex groups
219
+ regexPattern = regexPattern
220
+ .replace('2013', String.raw `(?<year>\d{2,4})`)
221
+ .replace('12', String.raw `(?<month>\d{1,2})`)
222
+ .replace('31', String.raw `(?<day>\d{1,2})`);
223
+ if (includeTime) {
224
+ regexPattern = regexPattern
225
+ .replaceAll(/17|5/g, String.raw `(?<hour>\d{1,2})`)
226
+ .replace('19', String.raw `(?<minute>\d{1,2})`)
227
+ .replace('22', String.raw `(?<second>\d{1,2})`)
228
+ .replaceAll(/AM|PM/gi, '(?<ampm>[APap][Mm])');
229
+ }
230
+ return regexPattern;
231
+ };
232
+ /**
233
+ * Helper function to try parsing with multiple patterns.
234
+ * @param dateString - The date string to parse.
235
+ * @param patterns - Array of format patterns to try.
236
+ * @param includeTime - Whether time parsing is included.
237
+ * @returns Parsed groups or null if no match.
238
+ */
239
+ const tryParseWithPatterns = (dateString, patterns, includeTime) => {
240
+ for (const pattern of patterns) {
241
+ const regexPattern = buildDateRegexPattern(pattern, includeTime);
242
+ const regex = new RegExp(`^${regexPattern}$`);
243
+ const match = dateString.trim().match(regex);
244
+ if (match?.groups) {
245
+ return match.groups;
246
+ }
247
+ }
248
+ return null;
249
+ };
250
+ /**
251
+ * Helper function to convert 12-hour to 24-hour format.
252
+ * @param hour - Hour string.
253
+ * @param ampm - AM/PM indicator.
254
+ * @returns Hour in 24-hour format.
255
+ */
256
+ const convertTo24Hour = (hour, ampm) => {
257
+ const parsedHour = Number.parseInt(hour, 10);
258
+ if (!ampm) {
259
+ return parsedHour;
260
+ }
261
+ const isPM = ampm.toLowerCase() === 'pm';
262
+ if (isPM && parsedHour !== 12) {
263
+ return parsedHour + 12;
264
+ }
265
+ if (!isPM && parsedHour === 12) {
266
+ return 0;
267
+ }
268
+ return parsedHour;
269
+ };
270
+ /**
271
+ * Helper function to validate time components.
272
+ * @param hour - Hour value.
273
+ * @param minute - Minute value.
274
+ * @param second - Second value.
275
+ * @returns True if time components are valid.
276
+ */
277
+ const validateTimeComponents = (hour, minute, second) => {
278
+ return hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59 && second >= 0 && second <= 59;
279
+ };
280
+ /**
281
+ * Helper function to validate date components.
282
+ * @param month - Month string.
283
+ * @param day - Day string.
284
+ * @returns True if date components are valid.
285
+ */
286
+ const validateDateComponents = (month, day) => {
287
+ const parsedMonth = Number.parseInt(month, 10) - 1;
288
+ const parsedDay = Number.parseInt(day, 10);
289
+ return parsedMonth >= 0 && parsedMonth <= 11 && parsedDay >= 1 && parsedDay <= 31;
290
+ };
291
+ /**
292
+ * Helper function to create date with time.
293
+ * @param groups - Parsed date and time groups.
294
+ * @returns Date object or null if invalid.
295
+ */
296
+ const createDateWithTime = (groups) => {
297
+ const { year, month, day, hour, minute, second, ampm } = groups;
298
+ const parsedYear = parseYearSmart(year);
299
+ const parsedMonth = Number.parseInt(month, 10) - 1;
300
+ const parsedDay = Number.parseInt(day, 10);
301
+ const parsedHour = convertTo24Hour(hour, ampm);
302
+ const parsedMinute = Number.parseInt(minute ?? '0', 10) || 0;
303
+ const parsedSecond = Number.parseInt(second ?? '0', 10) || 0;
304
+ if (!validateTimeComponents(parsedHour, parsedMinute, parsedSecond)) {
305
+ return null;
306
+ }
307
+ return new Date(parsedYear, parsedMonth, parsedDay, parsedHour, parsedMinute, parsedSecond);
308
+ };
309
+ /**
310
+ * Helper function to create date without time.
311
+ * @param groups - Parsed date groups.
312
+ * @returns Date object or null if invalid.
313
+ */
314
+ const createDateOnly = (groups) => {
315
+ const { year, month, day } = groups;
316
+ if (!validateDateComponents(month, day)) {
317
+ return null;
318
+ }
319
+ const parsedYear = parseYearSmart(year);
320
+ const parsedMonth = Number.parseInt(month, 10) - 1;
321
+ const parsedDay = Number.parseInt(day, 10);
322
+ return new Date(parsedYear, parsedMonth, parsedDay);
323
+ };
324
+ /**
325
+ * Enhanced day parsing with locale-aware patterns.
326
+ * @param dateString - The day string to parse.
327
+ * @param locale - The locale to use for parsing.
328
+ * @param includeTime - Whether to include time parsing.
329
+ * @returns Date object or null if invalid.
330
+ */
331
+ const parseDayString = (dateString, locale, includeTime) => {
332
+ const patterns = generateDatePatterns(locale, includeTime);
333
+ const groups = tryParseWithPatterns(dateString, patterns, includeTime);
334
+ if (!groups) {
335
+ // Check if input looks like a complete date (has separators and multiple parts)
336
+ // If so, use fallback parsing for formats like "2022/08/17", "2022-08-17"
337
+ // If not (like "1", "12"), return null
338
+ const trimmed = dateString.trim();
339
+ const hasDateSeparators = /[-/.:]/.test(trimmed);
340
+ const parts = trimmed.split(/[-/.\s:]+/).filter((part) => part.length > 0);
341
+ const hasMultipleParts = parts.length >= 2;
342
+ if (hasDateSeparators && hasMultipleParts) {
343
+ // Use fallback for complete date strings that don't match locale patterns
344
+ return parseLocalDateString(dateString);
345
+ }
346
+ // For incomplete input like "1" or "12", return null
347
+ return null;
348
+ }
349
+ // For day selection, require at least month and day to be present
350
+ if ('month' in groups && 'day' in groups) {
351
+ const { month, day } = groups;
352
+ if (!validateDateComponents(month, day)) {
353
+ return null;
354
+ }
355
+ }
356
+ else {
357
+ // If incomplete date information, return null instead of guessing
358
+ return null;
359
+ }
360
+ // Create and return appropriate date object
361
+ return includeTime
362
+ ? createDateWithTime(groups)
363
+ : createDateOnly(groups);
364
+ };
365
+ /**
366
+ * Parses a date string into a local Date object.
367
+ * @param dateString - The date string to parse.
368
+ * @returns The Date object in local timezone, or null if invalid.
369
+ */
370
+ const parseLocalDateString = (dateString) => {
371
+ const _date = new Date(Date.parse(dateString));
372
+ if (!Number.isNaN(_date.getTime())) {
373
+ return _date;
374
+ }
375
+ return null;
13
376
  };
14
377
  /**
15
378
  * Converts a date string or Date object to a Date object based on selection type.
16
379
  * @param date - The date to convert.
17
380
  * @param selectionType - The type of selection ('day', 'week', 'month', 'year').
381
+ * @param locale - The locale to use for date parsing (for day parsing).
382
+ * @param includeTime - Whether to include time parsing (for day parsing).
18
383
  * @returns The corresponding Date object or null if invalid.
19
384
  */
20
- const convertToDateObject = (date, selectionType) => {
385
+ const convertToDateObject = (date, selectionType, locale = 'en-US', includeTime = false) => {
386
+ if (date === null) {
387
+ return null;
388
+ }
21
389
  if (date instanceof Date) {
22
- return date;
390
+ return Number.isNaN(date.getTime()) ? null : date;
23
391
  }
24
- if (selectionType === 'week') {
25
- return convertIsoWeekToDate(date);
392
+ const dateString = date;
393
+ switch (selectionType) {
394
+ case 'week': {
395
+ return parseWeekString(dateString);
396
+ }
397
+ case 'month': {
398
+ return parseMonthString(dateString);
399
+ }
400
+ case 'year': {
401
+ return parseYearString(dateString);
402
+ }
403
+ default: {
404
+ // Enhanced day parsing with locale support
405
+ return parseDayString(dateString, locale, includeTime);
406
+ }
26
407
  }
27
- if (selectionType === 'month' || selectionType === 'year') {
28
- const _date = new Date(Date.parse(date));
29
- const userTimezoneOffset = _date.getTimezoneOffset() * 60_000;
30
- return new Date(_date.getTime() + userTimezoneOffset);
408
+ };
409
+ /**
410
+ * Enhanced locale-aware date parsing function (replaces getLocalDateFromString).
411
+ * @param dateString - The date string to parse.
412
+ * @param locale - The locale to use for date format patterns.
413
+ * @param includeTime - Whether to include time parsing.
414
+ * @param selectionType - The selection type ('day', 'week', 'month', 'year').
415
+ * @returns A Date object if parsing succeeds, null if parsing fails.
416
+ */
417
+ const getLocalDateFromString = (dateString, locale = 'en-US', includeTime = false, selectionType = 'day') => {
418
+ // Input validation
419
+ if (!dateString || typeof dateString !== 'string') {
420
+ return null;
31
421
  }
32
- return new Date(Date.parse(date));
422
+ return convertToDateObject(dateString, selectionType, locale, includeTime);
33
423
  };
34
424
  /**
35
425
  * Creates groups from an array.
@@ -58,7 +448,8 @@ const getCalendarDate = (calendarDate, order, view) => {
58
448
  return new Date(calendarDate.getFullYear() + order, calendarDate.getMonth(), 1);
59
449
  }
60
450
  if (order !== 0 && view === 'years') {
61
- return new Date(calendarDate.getFullYear() + 12 * order, calendarDate.getMonth(), 1);
451
+ // prettier-ignore
452
+ return new Date(calendarDate.getFullYear() + (12 * order), calendarDate.getMonth(), 1);
62
453
  }
63
454
  return calendarDate;
64
455
  };
@@ -197,7 +588,7 @@ const getISOWeekNumberAndYear = (date) => {
197
588
  tempDate.setDate(tempDate.getDate() + 3 - ((tempDate.getDay() + 6) % 7));
198
589
  const week1 = new Date(tempDate.getFullYear(), 0, 4);
199
590
  // Calculate full weeks to the date
200
- const weekNumber = 1 + Math.round((tempDate.getTime() - week1.getTime()) / 86_400_000 / 7);
591
+ const weekNumber = 1 + Math.round((tempDate.getTime() - week1.getTime()) / (86_400_000 * 7));
201
592
  return { weekNumber, year: tempDate.getFullYear() };
202
593
  };
203
594
  /**
@@ -222,9 +613,15 @@ const getMonthDetails = (year, month, firstDayOfWeek) => {
222
613
  }
223
614
  if ((index + 1) % 7 === 0) {
224
615
  const { weekNumber, year } = getISOWeekNumberAndYear(day.date);
225
- weeks[weeks.length - 1].week = { number: weekNumber, year };
616
+ const lastWeek = weeks.at(-1);
617
+ if (lastWeek) {
618
+ lastWeek.week = { number: weekNumber, year };
619
+ }
620
+ }
621
+ const lastWeek = weeks.at(-1);
622
+ if (lastWeek) {
623
+ lastWeek.days.push(day);
226
624
  }
227
- weeks[weeks.length - 1].days.push(day);
228
625
  });
229
626
  return weeks;
230
627
  };
@@ -278,7 +675,7 @@ const isDateInRange = (date, start, end) => {
278
675
  const _date = removeTimeFromDate(date);
279
676
  const _start = start ? removeTimeFromDate(start) : null;
280
677
  const _end = end ? removeTimeFromDate(end) : null;
281
- return !!(_start && _end && _start <= _date && _date <= _end);
678
+ return Boolean(_start && _end && _start <= _date && _date <= _end);
282
679
  };
283
680
  /**
284
681
  * Checks if a date is selected based on start and end dates.
@@ -327,23 +724,20 @@ const isDisableDateInRange = (startDate, endDate, disabledDates) => {
327
724
  * @returns True if the month is disabled, false otherwise.
328
725
  */
329
726
  const isMonthDisabled = (date, min, max, disabledDates) => {
330
- const current = date.getFullYear() * 12 + date.getMonth();
331
- const _min = min ? min.getFullYear() * 12 + min.getMonth() : null;
332
- const _max = max ? max.getFullYear() * 12 + max.getMonth() : null;
333
- if (_min && current < _min) {
334
- return true;
335
- }
336
- if (_max && current > _max) {
727
+ const current = dateToMonthNumber(date);
728
+ const _min = min ? dateToMonthNumber(min) : null;
729
+ const _max = max ? dateToMonthNumber(max) : null;
730
+ if (isOutsideRange(current, _min, _max)) {
337
731
  return true;
338
732
  }
339
733
  if (disabledDates === undefined) {
340
734
  return false;
341
735
  }
342
- const start = min ? Math.max(date.getTime(), min.getTime()) : date;
343
- const end = max
736
+ const startTime = min ? Math.max(date.getTime(), min.getTime()) : date.getTime();
737
+ const endTime = max
344
738
  ? Math.min(date.getTime(), max.getTime())
345
- : new Date(new Date().getFullYear(), 11, 31);
346
- for (const currentDate = new Date(start); currentDate <= end; currentDate.setDate(currentDate.getDate() + 1)) {
739
+ : new Date(new Date().getFullYear(), 11, 31).getTime();
740
+ for (const currentDate = new Date(startTime); currentDate.getTime() <= endTime; currentDate.setDate(currentDate.getDate() + 1)) {
347
741
  if (!isDateDisabled(currentDate, min, max, disabledDates)) {
348
742
  return false;
349
743
  }
@@ -376,12 +770,10 @@ const isMonthSelected = (date, start, end) => {
376
770
  * @returns True if the month is within the range, false otherwise.
377
771
  */
378
772
  const isMonthInRange = (date, start, end) => {
379
- const year = date.getFullYear();
380
- const month = date.getMonth();
381
- const _start = start ? start.getFullYear() * 12 + start.getMonth() : null;
382
- const _end = end ? end.getFullYear() * 12 + end.getMonth() : null;
383
- const _date = year * 12 + month;
384
- return !!(_start && _end && _start <= _date && _date <= _end);
773
+ const _start = start ? dateToMonthNumber(start) : null;
774
+ const _end = end ? dateToMonthNumber(end) : null;
775
+ const _date = dateToMonthNumber(date);
776
+ return Boolean(_start && _end && _start <= _date && _date <= _end);
385
777
  };
386
778
  /**
387
779
  * Checks if two dates are the same calendar date.
@@ -421,20 +813,17 @@ const isYearDisabled = (date, min, max, disabledDates) => {
421
813
  const year = date.getFullYear();
422
814
  const minYear = min ? min.getFullYear() : null;
423
815
  const maxYear = max ? max.getFullYear() : null;
424
- if (minYear && year < minYear) {
425
- return true;
426
- }
427
- if (maxYear && year > maxYear) {
816
+ if (isOutsideRange(year, minYear, maxYear)) {
428
817
  return true;
429
818
  }
430
819
  if (disabledDates === undefined) {
431
820
  return false;
432
821
  }
433
- const start = min ? Math.max(date.getTime(), min.getTime()) : date;
434
- const end = max
822
+ const startTime = min ? Math.max(date.getTime(), min.getTime()) : date.getTime();
823
+ const endTime = max
435
824
  ? Math.min(date.getTime(), max.getTime())
436
- : new Date(new Date().getFullYear(), 11, 31);
437
- for (const currentDate = new Date(start); currentDate <= end; currentDate.setDate(currentDate.getDate() + 1)) {
825
+ : new Date(new Date().getFullYear(), 11, 31).getTime();
826
+ for (const currentDate = new Date(startTime); currentDate.getTime() <= endTime; currentDate.setDate(currentDate.getDate() + 1)) {
438
827
  if (!isDateDisabled(currentDate, min, max, disabledDates)) {
439
828
  return false;
440
829
  }
@@ -469,7 +858,7 @@ const isYearInRange = (date, start, end) => {
469
858
  const year = date.getFullYear();
470
859
  const _start = start ? start.getFullYear() : null;
471
860
  const _end = end ? end.getFullYear() : null;
472
- return !!(_start && _end && _start <= year && year <= _end);
861
+ return Boolean(_start && _end && _start <= year && year <= _end);
473
862
  };
474
863
  /**
475
864
  * Removes the time component from a Date object.
@@ -499,13 +888,46 @@ const setTimeFromDate = (target, source) => {
499
888
  result.setHours(source.getHours(), source.getMinutes(), source.getSeconds(), source.getMilliseconds());
500
889
  return result;
501
890
  };
891
+ /**
892
+ * Parses a year string with smart 2-digit handling.
893
+ * @param yearString - The year string to parse.
894
+ * @returns The parsed year as a number with intelligent century assignment.
895
+ */
896
+ const parseYearSmart = (yearString) => {
897
+ let parsedYear = Number.parseInt(yearString, 10);
898
+ // Handle 2-digit years with intelligent century assignment
899
+ if (parsedYear < 100) {
900
+ const currentYear = new Date().getFullYear();
901
+ const currentCentury = Math.floor(currentYear / 100) * 100;
902
+ parsedYear = currentCentury + parsedYear;
903
+ // If the result is more than 50 years in the future, use previous century
904
+ // This creates a sliding window: for current year 2025, years 76-99 become 1976-1999
905
+ // and years 00-75 become 2000-2075
906
+ if (parsedYear > currentYear + 50) {
907
+ parsedYear -= 100;
908
+ }
909
+ }
910
+ return parsedYear;
911
+ };
912
+ /**
913
+ * Creates a date from year groups.
914
+ * @param groups - The year groups containing year string.
915
+ * @returns A Date object for January 1st of the year.
916
+ */
917
+ const createDateFromYear = (groups) => {
918
+ const { year } = groups;
919
+ const parsedYear = parseYearSmart(year);
920
+ return new Date(parsedYear, 0, 1);
921
+ };
502
922
 
503
923
  exports.convertIsoWeekToDate = convertIsoWeekToDate;
504
924
  exports.convertToDateObject = convertToDateObject;
925
+ exports.createDateFromYear = createDateFromYear;
505
926
  exports.createGroupsInArray = createGroupsInArray;
506
927
  exports.getCalendarDate = getCalendarDate;
507
928
  exports.getDateBySelectionType = getDateBySelectionType;
508
929
  exports.getISOWeekNumberAndYear = getISOWeekNumberAndYear;
930
+ exports.getLocalDateFromString = getLocalDateFromString;
509
931
  exports.getMonthDetails = getMonthDetails;
510
932
  exports.getMonthsNames = getMonthsNames;
511
933
  exports.getSelectableDates = getSelectableDates;
@@ -522,6 +944,7 @@ exports.isToday = isToday;
522
944
  exports.isYearDisabled = isYearDisabled;
523
945
  exports.isYearInRange = isYearInRange;
524
946
  exports.isYearSelected = isYearSelected;
947
+ exports.parseYearSmart = parseYearSmart;
525
948
  exports.removeTimeFromDate = removeTimeFromDate;
526
949
  exports.setTimeFromDate = setTimeFromDate;
527
950
  //# sourceMappingURL=utils.js.map