diff --git a/src/calendar/README.zh-CN.md b/src/calendar/README.zh-CN.md
index d4710d487..a74c02f01 100644
--- a/src/calendar/README.zh-CN.md
+++ b/src/calendar/README.zh-CN.md
@@ -251,7 +251,7 @@ export default {
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
-| type | 选择类型:
`single`表示选择单个日期,
`multiple`表示选择多个日期,
`range`表示选择日期区间 | _string_ | `single` |
+| type | 选择类型:
`single` 表示选择单个日期,
`multiple` 表示选择多个日期,
`range` 表示选择日期区间 | _string_ | `single` |
| title | 日历标题 | _string_ | `日期选择` |
| color | 主题色,对底部按钮和选中日期生效 | _string_ | `#ee0a24` |
| min-date | 可选择的最小日期 | _Date_ | 当前日期 |
diff --git a/src/calendar/components/Day.js b/src/calendar/components/Day.tsx
similarity index 77%
rename from src/calendar/components/Day.js
rename to src/calendar/components/Day.tsx
index f27091037..f59fd9b79 100644
--- a/src/calendar/components/Day.js
+++ b/src/calendar/components/Day.tsx
@@ -1,16 +1,43 @@
+import { computed, CSSProperties, PropType } from 'vue';
import { createNamespace } from '../../utils';
import { bem } from '../utils';
-import { computed } from 'vue';
const [createComponent] = createNamespace('calendar-day');
+export type DayType =
+ | ''
+ | 'start'
+ | 'start-end'
+ | 'middle'
+ | 'end'
+ | 'selected'
+ | 'multiple-middle'
+ | 'multiple-selected'
+ | 'disabled'
+ | 'placeholder';
+
+export type DayItem = {
+ date?: Date;
+ text?: string | number;
+ type?: DayType;
+ topInfo?: string;
+ className?: unknown;
+ bottomInfo?: string;
+};
+
export default createComponent({
props: {
- item: Object,
color: String,
index: Number,
- offset: Number,
rowHeight: String,
+ offset: {
+ type: Number,
+ default: 0,
+ },
+ item: {
+ type: Object as PropType,
+ required: true,
+ },
},
emits: ['click'],
@@ -18,7 +45,7 @@ export default createComponent({
setup(props, { emit }) {
const style = computed(() => {
const { item, index, color, offset, rowHeight } = props;
- const style = {
+ const style: CSSProperties = {
height: rowHeight,
};
@@ -92,7 +119,7 @@ export default createComponent({
role="gridcell"
style={style.value}
class={[bem('day', type), className]}
- tabindex={type === 'disabled' ? null : -1}
+ tabindex={type === 'disabled' ? undefined : -1}
onClick={onClick}
>
{renderContent()}
diff --git a/src/calendar/components/Header.js b/src/calendar/components/Header.tsx
similarity index 100%
rename from src/calendar/components/Header.js
rename to src/calendar/components/Header.tsx
diff --git a/src/calendar/components/Month.js b/src/calendar/components/Month.tsx
similarity index 80%
rename from src/calendar/components/Month.js
rename to src/calendar/components/Month.tsx
index 9af7decce..b2bb67e82 100644
--- a/src/calendar/components/Month.js
+++ b/src/calendar/components/Month.tsx
@@ -1,4 +1,4 @@
-import { ref, computed } from 'vue';
+import { ref, computed, PropType } from 'vue';
// Utils
import { addUnit, setScrollTop, createNamespace } from '../../utils';
@@ -18,26 +18,37 @@ import { useExpose } from '../../composables/use-expose';
import { useHeight } from '../../composables/use-height';
// Components
-import Day from './Day';
+import Day, { DayItem, DayType } from './Day';
const [createComponent] = createNamespace('calendar-month');
+export type CalendarType = 'single' | 'range' | 'multiple';
+
export default createComponent({
props: {
- date: Date,
- type: String,
+ type: String as PropType,
color: String,
- minDate: Date,
- maxDate: Date,
showMark: Boolean,
rowHeight: [Number, String],
- formatter: Function,
+ formatter: Function as PropType<(item: DayItem) => DayItem>,
lazyRender: Boolean,
- currentDate: [Date, Array],
+ currentDate: [Date, Array] as PropType,
allowSameDay: Boolean,
showSubtitle: Boolean,
showMonthTitle: Boolean,
firstDayOfWeek: Number,
+ date: {
+ type: Date as PropType,
+ required: true,
+ },
+ minDate: {
+ type: Date as PropType,
+ required: true,
+ },
+ maxDate: {
+ type: Date as PropType,
+ required: true,
+ },
},
emits: ['click', 'update-height'],
@@ -67,7 +78,7 @@ export default createComponent({
const getTitle = () => title.value;
- const scrollIntoView = (body) => {
+ const scrollIntoView = (body: Element) => {
const el = props.showSubtitle ? daysRef.value : monthRef.value;
const scrollTop =
@@ -78,9 +89,11 @@ export default createComponent({
setScrollTop(body, scrollTop);
};
- const getMultipleDayType = (day) => {
- const isSelected = (date) =>
- props.currentDate.some((item) => compareDay(item, date) === 0);
+ const getMultipleDayType = (day: Date) => {
+ const isSelected = (date: Date) =>
+ (props.currentDate as Date[]).some(
+ (item) => compareDay(item, date) === 0
+ );
if (isSelected(day)) {
const prevDay = getPrevDay(day);
@@ -103,8 +116,8 @@ export default createComponent({
return '';
};
- const getRangeDayType = (day) => {
- const [startDay, endDay] = props.currentDate;
+ const getRangeDayType = (day: Date) => {
+ const [startDay, endDay] = props.currentDate as Date[];
if (!startDay) {
return '';
@@ -130,9 +143,11 @@ export default createComponent({
if (compareToStart > 0 && compareToEnd < 0) {
return 'middle';
}
+
+ return '';
};
- const getDayType = (day) => {
+ const getDayType = (day: Date): DayType => {
const { type, minDate, maxDate, currentDate } = props;
if (compareDay(day, minDate) < 0 || compareDay(day, maxDate) > 0) {
@@ -140,7 +155,7 @@ export default createComponent({
}
if (currentDate === null) {
- return;
+ return '';
}
if (Array.isArray(currentDate)) {
@@ -151,11 +166,13 @@ export default createComponent({
return getRangeDayType(day);
}
} else if (type === 'single') {
- return compareDay(day, currentDate) === 0 ? 'selected' : '';
+ return compareDay(day, currentDate as Date) === 0 ? 'selected' : '';
}
+
+ return '';
};
- const getBottomInfo = (dayType) => {
+ const getBottomInfo = (dayType: DayType) => {
if (props.type === 'range') {
if (dayType === 'start' || dayType === 'end') {
return t(dayType);
@@ -179,7 +196,7 @@ export default createComponent({
};
const placeholders = computed(() => {
- const rows = [];
+ const rows: DayItem[] = [];
const count = Math.ceil((totalDay.value + offset.value) / 7);
for (let day = 1; day <= count; day++) {
rows.push({ type: 'placeholder' });
@@ -188,7 +205,7 @@ export default createComponent({
});
const days = computed(() => {
- const days = [];
+ const days: DayItem[] = [];
const year = props.date.getFullYear();
const month = props.date.getMonth();
@@ -196,7 +213,7 @@ export default createComponent({
const date = new Date(year, month, day);
const type = getDayType(date);
- let config = {
+ let config: DayItem = {
date,
type,
text: day,
@@ -213,7 +230,7 @@ export default createComponent({
return days;
});
- const renderDay = (item, index) => (
+ const renderDay = (item: DayItem, index: number) => (
,
+ formatter: Function as PropType<(item: DayItem) => DayItem>,
rowHeight: [Number, String],
confirmText: String,
rangePrompt: String,
- defaultDate: [Date, Array],
+ // TODO: remove any
+ // see: https://github.com/vuejs/vue-next/issues/2668
+ defaultDate: [Date, Array] as any,
allowSameDay: Boolean,
confirmDisabledText: String,
type: {
- type: String,
+ type: String as PropType,
default: 'single',
},
round: {
@@ -52,7 +57,7 @@ export default createComponent({
default: true,
},
position: {
- type: String,
+ type: String as PropType,
default: 'bottom',
},
poppable: {
@@ -96,14 +101,14 @@ export default createComponent({
default: true,
},
minDate: {
- type: Date,
+ type: Date as PropType,
validator: isDate,
default: () => new Date(),
},
maxDate: {
- type: Date,
+ type: Date as PropType,
validator: isDate,
- default() {
+ default: () => {
const now = new Date();
return new Date(now.getFullYear(), now.getMonth() + 6, now.getDate());
},
@@ -111,7 +116,7 @@ export default createComponent({
firstDayOfWeek: {
type: [Number, String],
default: 0,
- validator: (val) => val >= 0 && val <= 6,
+ validator: (val: number) => val >= 0 && val <= 6,
},
},
@@ -119,7 +124,7 @@ export default createComponent({
setup(props, { emit, slots }) {
const limitDateRange = (
- date,
+ date: Date,
minDate = props.minDate,
maxDate = props.maxDate
) => {
@@ -167,7 +172,7 @@ export default createComponent({
return limitDateRange(defaultDate);
};
- let bodyHeight;
+ let bodyHeight: number;
const bodyRef = ref();
@@ -176,10 +181,10 @@ export default createComponent({
currentDate: getInitialDate(),
});
- const [monthRefs, setMonthRefs] = useRefs();
+ const [monthRefs, setMonthRefs] = useRefs();
const dayOffset = computed(() =>
- props.firstDayOfWeek ? props.firstDayOfWeek % 7 : 0
+ props.firstDayOfWeek ? +props.firstDayOfWeek % 7 : 0
);
const months = computed(() => {
@@ -201,10 +206,10 @@ export default createComponent({
if (currentDate) {
if (props.type === 'range') {
- return !currentDate[0] || !currentDate[1];
+ return !(currentDate as Date[])[0] || !(currentDate as Date[])[1];
}
if (props.type === 'multiple') {
- return !currentDate.length;
+ return !(currentDate as Date[]).length;
}
}
@@ -267,7 +272,7 @@ export default createComponent({
}
};
- const scrollToDate = (targetDate) => {
+ const scrollToDate = (targetDate: Date) => {
raf(() => {
months.value.some((month, index) => {
if (compareMonth(month, targetDate) === 0) {
@@ -291,7 +296,7 @@ export default createComponent({
const { currentDate } = state;
if (currentDate) {
const targetDate =
- props.type === 'single' ? currentDate : currentDate[0];
+ props.type === 'single' ? currentDate : (currentDate as Date[])[0];
scrollToDate(targetDate);
} else {
raf(onScroll);
@@ -316,7 +321,7 @@ export default createComponent({
scrollIntoView();
};
- const checkRange = (date) => {
+ const checkRange = (date: [Date, Date]) => {
const { maxRange, rangePrompt } = props;
if (maxRange && calcDateNum(date) > maxRange) {
@@ -331,21 +336,21 @@ export default createComponent({
emit('confirm', copyDates(state.currentDate));
};
- const select = (date, complete) => {
- const setCurrentDate = (date) => {
+ const select = (date: Date | Date[], complete?: boolean) => {
+ const setCurrentDate = (date: Date | Date[]) => {
state.currentDate = date;
emit('select', copyDates(state.currentDate));
};
if (complete && props.type === 'range') {
- const valid = checkRange(date);
+ const valid = checkRange(date as [Date, Date]);
if (!valid) {
// auto selected to max range if showConfirm
if (props.showConfirm) {
setCurrentDate([
- date[0],
- getDayByOffset(date[0], props.maxRange - 1),
+ (date as Date[])[0],
+ getDayByOffset((date as Date[])[0], +props.maxRange - 1),
]);
} else {
setCurrentDate(date);
@@ -361,8 +366,8 @@ export default createComponent({
}
};
- const onClickDay = (item) => {
- if (props.readonly) {
+ const onClickDay = (item: DayItem) => {
+ if (props.readonly || !item.date) {
return;
}
@@ -372,7 +377,7 @@ export default createComponent({
if (type === 'range') {
if (!currentDate) {
- select([date, null]);
+ select([date]);
return;
}
@@ -384,12 +389,12 @@ export default createComponent({
if (compareToStart === 1) {
select([startDay, date], true);
} else if (compareToStart === -1) {
- select([date, null]);
+ select([date]);
} else if (props.allowSameDay) {
select([date, date], true);
}
} else {
- select([date, null]);
+ select([date]);
}
} else if (type === 'multiple') {
if (!currentDate) {
@@ -398,13 +403,15 @@ export default createComponent({
}
let selectedIndex;
- const selected = state.currentDate.some((dateItem, index) => {
- const equal = compareDay(dateItem, date) === 0;
- if (equal) {
- selectedIndex = index;
+ const selected = state.currentDate.some(
+ (dateItem: Date, index: number) => {
+ const equal = compareDay(dateItem, date) === 0;
+ if (equal) {
+ selectedIndex = index;
+ }
+ return equal;
}
- return equal;
- });
+ );
if (selected) {
const [unselectedDate] = currentDate.splice(selectedIndex, 1);
@@ -419,11 +426,11 @@ export default createComponent({
}
};
- const togglePopup = (val) => {
- emit('update:show', val);
+ const togglePopup = (value: boolean) => {
+ emit('update:show', value);
};
- const renderMonth = (date, index) => {
+ const renderMonth = (date: Date, index: number) => {
const showMonthTitle = index !== 0 || !props.showSubtitle;
return (