|
23 | 23 |
|
24 | 24 | function setValue(d: Date) { |
25 | 25 | if (d.getTime() !== value?.getTime()) { |
26 | | - browseDate = clamp(d, min, max) |
| 26 | + browseDate = getValidDate(value, d) |
27 | 27 | applyTimePrecision(browseDate, timePrecision) |
28 | 28 | value = cloneDate(browseDate) |
29 | 29 | } |
30 | 30 | } |
31 | 31 |
|
32 | | - function setValueDate(d: Date) { |
33 | | - if (d.getTime() !== value?.getTime()) { |
34 | | - browseDate = clampDate(d, min, max) |
35 | | - value = cloneDate(browseDate) |
36 | | - } |
37 | | - } |
38 | | -
|
39 | 32 | /** Set the browseDate */ |
40 | 33 | function browse(d: Date) { |
41 | 34 | browseDate = clampDate(d, min, max) |
|
70 | 63 | return isDisabledDate?.(new Date(date.year, date.month, date.number)) |
71 | 64 | } |
72 | 65 |
|
| 66 | + function getValidDate(oldDate: Date | null, newDate: Date | null): Date { |
| 67 | + if (!newDate) return new Date(defaultDate) |
| 68 | + if (!oldDate) oldDate = new Date(defaultDate) |
| 69 | +
|
| 70 | + // This creates a new Date object to avoid mutating the original newDate |
| 71 | + // this leads to unintended side effects elsewhere in the program if this is not done |
| 72 | + let adjustedDate = new Date(newDate) |
| 73 | +
|
| 74 | + if (oldDate > newDate) { |
| 75 | + adjustDate(adjustedDate, -1) |
| 76 | + if (adjustedDate < min) { |
| 77 | + adjustedDate = new Date(min) |
| 78 | + // Adjusts the date one more time if the min date is disabled, to ensure a valid, enabled date is selected |
| 79 | + adjustDate(adjustedDate, 1) |
| 80 | + } |
| 81 | + return adjustedDate |
| 82 | + } |
| 83 | + if (adjustedDate > oldDate) { |
| 84 | + adjustDate(adjustedDate, 1) |
| 85 | + if (adjustedDate > max) { |
| 86 | + adjustedDate = new Date(max) |
| 87 | + // Adjusts the date one more time if the max date is disabled, to ensure a valid, enabled date is selected |
| 88 | + adjustDate(adjustedDate, -1) |
| 89 | + } |
| 90 | + return adjustedDate |
| 91 | + } |
| 92 | + return adjustedDate |
| 93 | +
|
| 94 | + function adjustDate(date: Date, increment: number) { |
| 95 | + // Prevents accidental infinite loops |
| 96 | + const MAXLOOPS = 36525 // ~100 years, should be large enough |
| 97 | + let loopCount: number = 0 |
| 98 | +
|
| 99 | + while (isDisabledDate?.(date) && date >= min && date <= max && loopCount <= MAXLOOPS) { |
| 100 | + date.setDate(date.getDate() + increment) |
| 101 | + loopCount++ |
| 102 | + } |
| 103 | + } |
| 104 | + } |
| 105 | +
|
| 106 | + // Prevents a invalid date from being typed into the Dateinput text box |
73 | 107 | $: if (value && value > max) { |
74 | | - setValue(max) |
| 108 | + setValue(getValidDate(value, max)) |
75 | 109 | } else if (value && value < min) { |
76 | | - setValue(min) |
| 110 | + setValue(getValidDate(value, min)) |
| 111 | + } else if (value && isDisabledDate?.(value)) { |
| 112 | + setValue(getValidDate(defaultDate, value)) |
77 | 113 | } |
78 | 114 | function clamp(d: Date, min: Date, max: Date) { |
79 | 115 | if (d > max) { |
|
170 | 206 | browseDate.setFullYear(calendarDay.year) |
171 | 207 | browseDate.setMonth(calendarDay.month) |
172 | 208 | browseDate.setDate(calendarDay.number) |
173 | | - setValueDate(browseDate) |
| 209 | + setValue(browseDate) |
174 | 210 | dispatch('select', cloneDate(browseDate)) |
175 | 211 | } |
176 | 212 | } |
|
243 | 279 | return |
244 | 280 | } else if (e.key === 'ArrowUp') { |
245 | 281 | browseDate.setDate(browseDate.getDate() - 7) |
246 | | - setValueDate(browseDate) |
| 282 | + setValue(browseDate) |
247 | 283 | } else if (e.key === 'ArrowDown') { |
248 | 284 | browseDate.setDate(browseDate.getDate() + 7) |
249 | | - setValueDate(browseDate) |
| 285 | + setValue(browseDate) |
250 | 286 | } else if (e.key === 'ArrowLeft') { |
251 | 287 | browseDate.setDate(browseDate.getDate() - 1) |
252 | | - setValueDate(browseDate) |
| 288 | + setValue(browseDate) |
253 | 289 | } else if (e.key === 'ArrowRight') { |
254 | 290 | browseDate.setDate(browseDate.getDate() + 1) |
255 | | - setValueDate(browseDate) |
| 291 | + setValue(browseDate) |
256 | 292 | } else if (e.key === 'Enter') { |
257 | 293 | setValue(browseDate) |
258 | 294 | dispatch('select', cloneDate(browseDate)) |
|
0 commit comments