Skip to content

Commit 1b5da06

Browse files
committed
feat: valid range support
1 parent 7408a8c commit 1b5da06

File tree

3 files changed

+76
-3
lines changed

3 files changed

+76
-3
lines changed

src/Date/Calendar.tsx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
dateToUnix,
1010
DisableWeekDaysType,
1111
getInitialIndex,
12+
isDateWithinOptionalRange,
1213
} from './dateUtils'
1314

1415
import CalendarHeader from './CalendarHeader'
@@ -22,9 +23,15 @@ export type ModeType = 'single' | 'range' | 'excludeInRange' | 'multiple'
2223

2324
export type ScrollModeType = 'horizontal' | 'vertical'
2425

26+
export type ValidRangeType = {
27+
startDate?: Date
28+
endDate?: Date
29+
}
30+
2531
export type BaseCalendarProps = {
2632
locale?: undefined | string
2733
disableWeekDays?: DisableWeekDaysType
34+
validRange?: ValidRangeType
2835
}
2936

3037
export type CalendarDate = Date | undefined
@@ -95,6 +102,7 @@ function Calendar(
95102
disableWeekDays,
96103
// @ts-ignore
97104
dates,
105+
validRange,
98106
} = props
99107

100108
const theme = useTheme()
@@ -131,8 +139,27 @@ function Calendar(
131139
>(onChange)
132140
const datesRef = useLatest<Date[]>(dates)
133141

142+
// Dates => primitives (memoized & trigger re-renders as needed)
143+
const validRangeStart =
144+
validRange?.startDate instanceof Date
145+
? validRange?.startDate?.toISOString()
146+
: null
147+
const validRangeEnd =
148+
validRange?.endDate instanceof Date
149+
? validRange?.endDate?.toISOString()
150+
: null
151+
134152
const onPressDate = useCallback(
135153
(d: Date) => {
154+
const isWithinValidRange = isDateWithinOptionalRange(d, {
155+
startDate: validRangeStart ? new Date(validRangeStart) : undefined,
156+
endDate: validRangeEnd ? new Date(validRangeEnd) : undefined,
157+
})
158+
159+
if (!isWithinValidRange) {
160+
return
161+
}
162+
136163
if (mode === 'single') {
137164
;(onChangeRef.current as SingleChange)({
138165
date: d,
@@ -180,7 +207,16 @@ function Calendar(
180207
})
181208
}
182209
},
183-
[mode, onChangeRef, startDateRef, endDateRef, excludedDatesRef, datesRef]
210+
[
211+
validRangeStart,
212+
validRangeEnd,
213+
mode,
214+
onChangeRef,
215+
startDateRef,
216+
endDateRef,
217+
excludedDatesRef,
218+
datesRef,
219+
]
184220
)
185221

186222
return (
@@ -194,6 +230,7 @@ function Calendar(
194230
locale={locale}
195231
mode={mode}
196232
key={index}
233+
validRange={validRange}
197234
index={index}
198235
startDate={startDate}
199236
endDate={endDate}

src/Date/DatePickerModalContent.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export function DatePickerModalContent(
9191
disableSafeTop,
9292
disableWeekDays,
9393
locale,
94+
validRange,
9495
} = props
9596

9697
const anyProps = props as any
@@ -193,6 +194,7 @@ export function DatePickerModalContent(
193194
onChange={onInnerChange}
194195
disableWeekDays={disableWeekDays}
195196
dates={state.dates}
197+
validRange={validRange}
196198
/>
197199
}
198200
calendarEdit={

src/Date/Month.tsx

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ import {
1818
startAtIndex,
1919
beginOffset,
2020
estimatedMonthHeight,
21+
isDateWithinOptionalRange,
2122
} from './dateUtils'
2223
import { getCalendarHeaderHeight } from './CalendarHeader'
23-
import { ModeType } from './Calendar'
24+
import type { ModeType, ValidRangeType } from './Calendar'
2425
import { dayNamesHeight } from './DayNames'
2526
import { useTextColorOnPrimary } from '../utils'
2627

@@ -40,6 +41,7 @@ interface BaseMonthProps {
4041
primaryColor: string
4142
selectColor: string
4243
roundness: number
44+
validRange?: ValidRangeType
4345
}
4446

4547
interface MonthRangeProps extends BaseMonthProps {
@@ -82,6 +84,7 @@ function Month({
8284
locale,
8385
// @ts-ignore
8486
dates,
87+
validRange,
8588
}:
8689
| MonthSingleProps
8790
| MonthRangeProps
@@ -92,6 +95,16 @@ function Month({
9295
const realIndex = getRealIndex(index)
9396
const isHorizontal = scrollMode === 'horizontal'
9497

98+
const validRangeStart =
99+
validRange?.startDate instanceof Date
100+
? validRange?.startDate?.toISOString()
101+
: null
102+
103+
const validRangeEnd =
104+
validRange?.endDate instanceof Date
105+
? validRange?.endDate?.toISOString()
106+
: null
107+
95108
const { monthName, month, year } = React.useMemo(() => {
96109
const md = addMonths(new Date(), realIndex)
97110
const y = md.getFullYear()
@@ -125,6 +138,11 @@ function Month({
125138
const selectedEndDay = areDatesOnSameDay(day, endDate)
126139
const selectedDay = areDatesOnSameDay(day, date)
127140

141+
const isWithinOptionalValidRange = isDateWithinOptionalRange(day, {
142+
startDate: validRangeStart ? new Date(validRangeStart) : undefined,
143+
endDate: validRangeEnd ? new Date(validRangeEnd) : undefined,
144+
})
145+
128146
const multiDates = dates as Date[] | undefined
129147

130148
const selectedMultiDay = !!multiDates?.some((d) =>
@@ -151,6 +169,10 @@ function Month({
151169
disabled = false
152170
}
153171

172+
if (!isWithinOptionalValidRange) {
173+
disabled = true
174+
}
175+
154176
let leftCrop: boolean = selectedStartDay || dayOfMonth === 1
155177
let rightCrop: boolean = selectedEndDay || dayOfMonth === daysInMonth
156178

@@ -208,7 +230,19 @@ function Month({
208230
}),
209231
}
210232
})
211-
}, [year, month, index, startDate, endDate, date, dates, mode, excludedDates])
233+
}, [
234+
year,
235+
month,
236+
index,
237+
startDate,
238+
endDate,
239+
date,
240+
validRangeStart,
241+
validRangeEnd,
242+
dates,
243+
mode,
244+
excludedDates,
245+
])
212246

213247
return (
214248
<View style={[styles.month, { height: getMonthHeight(scrollMode, index) }]}>

0 commit comments

Comments
 (0)