Skip to content

Commit aa89838

Browse files
author
stinger567
committed
added checks to prevent selecting a disabled date by typing or from arrow keys
1 parent c1f5a2f commit aa89838

File tree

1 file changed

+51
-15
lines changed

1 file changed

+51
-15
lines changed

src/lib/DatePicker.svelte

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,12 @@
2323
2424
function setValue(d: Date) {
2525
if (d.getTime() !== value?.getTime()) {
26-
browseDate = clamp(d, min, max)
26+
browseDate = getValidDate(value, d)
2727
applyTimePrecision(browseDate, timePrecision)
2828
value = cloneDate(browseDate)
2929
}
3030
}
3131
32-
function setValueDate(d: Date) {
33-
if (d.getTime() !== value?.getTime()) {
34-
browseDate = clampDate(d, min, max)
35-
value = cloneDate(browseDate)
36-
}
37-
}
38-
3932
/** Set the browseDate */
4033
function browse(d: Date) {
4134
browseDate = clampDate(d, min, max)
@@ -70,10 +63,53 @@
7063
return isDisabledDate?.(new Date(date.year, date.month, date.number))
7164
}
7265
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
73107
$: if (value && value > max) {
74-
setValue(max)
108+
setValue(getValidDate(value, max))
75109
} else if (value && value < min) {
76-
setValue(min)
110+
setValue(getValidDate(value, min))
111+
} else if (value && isDisabledDate?.(value)) {
112+
setValue(getValidDate(defaultDate, value))
77113
}
78114
function clamp(d: Date, min: Date, max: Date) {
79115
if (d > max) {
@@ -170,7 +206,7 @@
170206
browseDate.setFullYear(calendarDay.year)
171207
browseDate.setMonth(calendarDay.month)
172208
browseDate.setDate(calendarDay.number)
173-
setValueDate(browseDate)
209+
setValue(browseDate)
174210
dispatch('select', cloneDate(browseDate))
175211
}
176212
}
@@ -243,16 +279,16 @@
243279
return
244280
} else if (e.key === 'ArrowUp') {
245281
browseDate.setDate(browseDate.getDate() - 7)
246-
setValueDate(browseDate)
282+
setValue(browseDate)
247283
} else if (e.key === 'ArrowDown') {
248284
browseDate.setDate(browseDate.getDate() + 7)
249-
setValueDate(browseDate)
285+
setValue(browseDate)
250286
} else if (e.key === 'ArrowLeft') {
251287
browseDate.setDate(browseDate.getDate() - 1)
252-
setValueDate(browseDate)
288+
setValue(browseDate)
253289
} else if (e.key === 'ArrowRight') {
254290
browseDate.setDate(browseDate.getDate() + 1)
255-
setValueDate(browseDate)
291+
setValue(browseDate)
256292
} else if (e.key === 'Enter') {
257293
setValue(browseDate)
258294
dispatch('select', cloneDate(browseDate))

0 commit comments

Comments
 (0)