Skip to content

Commit bcebe67

Browse files
committed
feat: support excluding date
1 parent bdd74bd commit bcebe67

5 files changed

Lines changed: 58 additions & 23 deletions

File tree

packages/react-use-calendar-component/src/app/components/CalendarCell.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,30 @@ import type { DateCellInfo } from '../../lib/types';
33
export default function CalendarCell({
44
monthStatus,
55
isSelected,
6+
isExcluded,
67
isToday,
78
monthDay,
89
selectThisDate,
910
}: DateCellInfo) {
1011
const title = isToday ? 'today' : undefined;
1112
let className = 'rounded-full';
12-
if (monthStatus !== 'current') className = `${className} text-slate-300`;
13-
if (isSelected) className = `${className} bg-green-200 selected`;
14-
if (isToday && !isSelected) className = `${className} bg-amber-200`;
15-
if (!isToday && !isSelected) className = `${className} hover:bg-stone-100`;
13+
if (monthStatus !== 'current' || isExcluded)
14+
className = `${className} text-slate-300`;
15+
16+
// set background color
17+
const decorator = (() => {
18+
if (isSelected) return 'bg-green-200';
19+
if (isToday) return 'bg-amber-200';
20+
if (isExcluded) return 'bg-gray-100 cursor-not-allowed';
21+
return '';
22+
})();
23+
className = `${className} ${decorator}`;
24+
if (!isToday && !isSelected && !isExcluded)
25+
className = `${className} hover:bg-stone-100`;
1626

1727
return (
1828
<button
29+
disabled={isExcluded}
1930
className={`${className} ${monthStatus}`}
2031
onClick={() => selectThisDate()}
2132
type='button'

packages/react-use-calendar-component/src/lib/hooks/useCalendarComponent.ts

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,21 @@ import type {
88
SelectType,
99
Value,
1010
} from '../types';
11-
import { getDateInfoByIndex, isSameDate, noop } from '../utils';
12-
import { normalizeValue } from '../utils/normalizeValue';
11+
import {
12+
getDateInfoByIndex,
13+
isSameDate,
14+
isExcludedDate,
15+
noop,
16+
normalizeValue,
17+
} from '../utils';
1318
import useDisplayedDate from './useDisplayedDate';
1419

1520
export default function useCalendarComponent<S extends SelectType = 'single'>({
1621
initialDisplayedDate = new Date(),
1722
selectType,
1823
value: userValue,
1924
onChange = noop,
25+
excludedDates = {},
2026
}: UseCalendarOptions<S> = {}) {
2127
const {
2228
displayedYear,
@@ -45,30 +51,23 @@ export default function useCalendarComponent<S extends SelectType = 'single'>({
4551
monthDay,
4652
...info
4753
} = getDateInfoByIndex(year, month, cellIndex);
48-
49-
const isSelected = !!selectedDates.find(date =>
50-
isSameDate(date, new Date(dateYear, dateMonth, monthDay))
51-
);
54+
const thisDate = new Date(dateYear, dateMonth, monthDay);
55+
const isSelected = !!selectedDates.find(d => isSameDate(d, thisDate));
56+
const isExcluded = isExcludedDate(thisDate, excludedDates);
5257
const selectThisDate = (options: SelectDateOptions = {}) => {
5358
const { changeDisplayedValues = true } = options;
5459
if (changeDisplayedValues) {
5560
setDisplayedYear(dateYear);
5661
setDisplayedMonth(dateMonth);
5762
}
58-
const selectedDate = new Date(dateYear, dateMonth, monthDay);
5963
if (selectType === 'multiple') {
60-
const newDates = selectedDates.filter(
61-
date => !isSameDate(date, selectedDate)
62-
);
63-
if (newDates.length === selectedDates.length)
64-
newDates.push(selectedDate);
65-
newDates.sort((a, b) => a.getTime() - b.getTime());
64+
const newDates = selectedDates.filter(d => !isSameDate(d, thisDate));
65+
if (newDates.length === selectedDates.length) newDates.push(thisDate);
6666
handleValueChange(newDates as any);
6767

6868
return;
6969
}
70-
71-
handleValueChange(selectedDate as any);
70+
handleValueChange(thisDate as any);
7271
};
7372

7473
return {
@@ -77,15 +76,13 @@ export default function useCalendarComponent<S extends SelectType = 'single'>({
7776
month: dateMonth,
7877
monthDay,
7978
isSelected,
79+
isExcluded,
8080
selectThisDate,
8181
...info,
8282
};
8383
};
8484

85-
const getDateCellInfos = (
86-
year: number = displayedYear,
87-
month: number = displayedMonth
88-
) => {
85+
const getDateCellInfos = (year = displayedYear, month = displayedMonth) => {
8986
const arr: DateCellInfo[] = [];
9087
for (let i = 0; i < CALENDAR_CELLS_NUM; i++) {
9188
arr.push(getDateCellInfo(year, month, i));

packages/react-use-calendar-component/src/lib/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,18 @@ export type Value<S extends SelectType> = S extends 'single'
77
? Date[]
88
: never;
99

10+
export type ExcludedDates = {
11+
min?: Date;
12+
max?: Date;
13+
arbitrary?: Date[];
14+
};
15+
1016
export type UseCalendarOptions<S extends SelectType = 'single'> = {
1117
initialDisplayedDate?: Date;
1218
selectType?: S;
1319
value?: Value<S>;
1420
onChange?: (value: Value<S>) => void;
21+
excludedDates?: ExcludedDates;
1522
};
1623

1724
export interface DateInfo {
@@ -26,6 +33,7 @@ export interface DateInfo {
2633
export interface DateCellInfo extends DateInfo {
2734
key: string;
2835
isSelected: boolean;
36+
isExcluded: boolean;
2937
selectThisDate: (options?: SelectDateOptions) => void;
3038
}
3139

packages/react-use-calendar-component/src/lib/utils/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ export * from './locale';
44
export * from './getDateInfoByIndex';
55
export * from './noop';
66
export * from './isSameDate';
7+
export * from './normalizeValue';
8+
export * from './isExcludedDate';
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { ExcludedDates } from '../types';
2+
import { isSameDate } from './isSameDate';
3+
4+
function largerThan(a: Date, b: Date) {
5+
return a.getTime() > b.getTime();
6+
}
7+
8+
export function isExcludedDate(
9+
date: Date,
10+
{ min, max, arbitrary }: ExcludedDates
11+
) {
12+
if (min && !largerThan(date, min)) return true;
13+
if (max && largerThan(date, max)) return true;
14+
if (arbitrary && !!arbitrary.find(d => isSameDate(d, date))) return true;
15+
16+
return false;
17+
}

0 commit comments

Comments
 (0)