Skip to content

Commit 9684363

Browse files
author
Bedram Tamang
committed
feat: holiday feature
1 parent 94b77c1 commit 9684363

File tree

3 files changed

+78
-3
lines changed

3 files changed

+78
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
.idea
12
.vscode
23
.cache
34
.DS_Store

__tests__/Calendar.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,58 @@ describe('CalendarPanel', () => {
9696
expect(mockFn).not.toHaveBeenCalled();
9797
});
9898

99+
[true, false].forEach((holidayClickable) => {
100+
it('props: holidayClickable', () => {
101+
const holidayDate = (date: Date) => {
102+
return date === new Date(2019, 9, 1);
103+
};
104+
const mockFn = jest.fn();
105+
wrapper = mount(Calendar, {
106+
props: {
107+
value: new Date(2019, 9, 1),
108+
['onUpdate:value']: mockFn,
109+
holidayClickable: holidayClickable,
110+
holidayDate: holidayDate,
111+
},
112+
});
113+
wrapper.find('.mx-table-date td').trigger('click');
114+
115+
if (holidayClickable) {
116+
expect(mockFn).toHaveBeenCalled();
117+
} else {
118+
expect(mockFn).not.toHaveBeenCalled();
119+
}
120+
});
121+
});
122+
123+
it('prop: holidayDate', () => {
124+
const holidayDate = (date: Date) => {
125+
return date < new Date(2019, 9, 1) || date > new Date(2019, 9, 20);
126+
};
127+
const mockFn = jest.fn();
128+
wrapper = mount(Calendar, {
129+
props: {
130+
value: new Date(2019, 9, 4),
131+
['onUpdate:value']: mockFn,
132+
holidayClickable: false,
133+
holidayDate: holidayDate,
134+
},
135+
});
136+
const tds = wrapper.findAll('.mx-table-date td');
137+
for (let i = 0; i < 42; i++) {
138+
const td = tds[i];
139+
const classes = td.classes();
140+
if (i < 2 || i > 21) {
141+
expect(classes).toContain('holiday');
142+
} else {
143+
expect(classes).not.toContain('holiday');
144+
}
145+
}
146+
147+
tds[1].trigger('click');
148+
expect(mockFn).not.toHaveBeenCalled();
149+
});
150+
99151
const renderType = (type: 'date' | 'month' | 'year') => {
100152
it(`prop: type=${type}`, () => {
101153
wrapper = mount(Calendar, {

lib/calendar/Calendar.tsx

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { computed, ref, watchEffect } from 'vue';
2+
import { PanelType, PickerType } from '../type';
23
import {
34
getValidDate,
45
isValidDate,
@@ -8,18 +9,19 @@ import {
89
startOfMonth,
910
startOfYear,
1011
} from '../util/date';
12+
import { defineVueComponent, keys, withDefault } from '../vueUtil';
1113
import { TableDate } from './TableDate';
1214
import { TableMonth } from './TableMonth';
1315
import { TableYear } from './TableYear';
14-
import { PanelType, PickerType } from '../type';
15-
import { defineVueComponent, keys, withDefault } from '../vueUtil';
1616

1717
export interface CalendarProps {
1818
type?: PickerType;
1919
value?: Date | Date[];
2020
defaultValue?: Date;
2121
defaultPanel?: PickerType;
2222
disabledDate?: (value: Date, innerValue?: Date[]) => boolean;
23+
holidayClickable?: boolean;
24+
holidayDate?: (value: Date, innerValue?: Date[]) => boolean;
2325
getClasses?: (value: Date, innerValue: Date[], classes: string) => string[] | string;
2426
calendar?: Date;
2527
multiple?: boolean;
@@ -40,6 +42,8 @@ function Calendar(originalProps: CalendarProps) {
4042
defaultValue: startOfDay(new Date()),
4143
type: 'date' as PickerType,
4244
disabledDate: () => false,
45+
holidayClickable: () => false,
46+
holidayDate: () => false,
4347
getClasses: () => [],
4448
titleFormat: 'YYYY-MM-DD',
4549
});
@@ -85,8 +89,22 @@ function Calendar(originalProps: CalendarProps) {
8589
return props.disabledDate(new Date(date), innerValue.value);
8690
};
8791

92+
const isHoliday = (date: Date) => {
93+
return props.holidayDate(new Date(date), innerValue.value);
94+
};
95+
96+
const isClickable = (date: Date) => {
97+
if (isDisabled(date)) {
98+
return false;
99+
}
100+
if (!props.holidayClickable && isHoliday(date)) {
101+
return false;
102+
}
103+
return true;
104+
};
105+
88106
const emitDate = (date: Date, type: string) => {
89-
if (!isDisabled(date)) {
107+
if (isClickable(date)) {
90108
props.onPick?.(date);
91109
if (props.multiple === true) {
92110
const nextDates = innerValue.value.filter((v) => v.getTime() !== date.getTime());
@@ -133,6 +151,8 @@ function Calendar(originalProps: CalendarProps) {
133151
const getCellClasses = (cellDate: Date, classes: string[] = []) => {
134152
if (isDisabled(cellDate)) {
135153
classes.push('disabled');
154+
} else if (isHoliday(cellDate)) {
155+
classes.push('holiday');
136156
} else if (innerValue.value.some((v) => v.getTime() === cellDate.getTime())) {
137157
classes.push('active');
138158
}
@@ -222,6 +242,8 @@ export const calendarProps = keys<CalendarProps>()([
222242
'defaultValue',
223243
'defaultPanel',
224244
'disabledDate',
245+
'holidayDate',
246+
'holidayClickable',
225247
'getClasses',
226248
'calendar',
227249
'multiple',

0 commit comments

Comments
 (0)