types(Calendar): use tsx (#8180)

This commit is contained in:
neverland 2021-02-19 19:46:46 +08:00 committed by GitHub
parent 8696f4ee70
commit d092d669f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 120 additions and 69 deletions

View File

@ -251,7 +251,7 @@ export default {
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| type | 选择类型:<br>`single`表示选择单个日期,<br>`multiple`表示选择多个日期,<br>`range`表示选择日期区间 | _string_ | `single` |
| type | 选择类型:<br>`single` 表示选择单个日期,<br>`multiple` 表示选择多个日期,<br>`range` 表示选择日期区间 | _string_ | `single` |
| title | 日历标题 | _string_ | `日期选择` |
| color | 主题色,对底部按钮和选中日期生效 | _string_ | `#ee0a24` |
| min-date | 可选择的最小日期 | _Date_ | 当前日期 |

View File

@ -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<DayItem>,
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()}

View File

@ -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<CalendarType>,
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<Date | Date[]>,
allowSameDay: Boolean,
showSubtitle: Boolean,
showMonthTitle: Boolean,
firstDayOfWeek: Number,
date: {
type: Date as PropType<Date>,
required: true,
},
minDate: {
type: Date as PropType<Date>,
required: true,
},
maxDate: {
type: Date as PropType<Date>,
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) => (
<Day
item={item}
index={index}

View File

@ -1,7 +1,7 @@
import { ref, watch, reactive, computed } from 'vue';
import { ref, watch, reactive, computed, PropType, TeleportProps } from 'vue';
// Utils
import { pick, getScrollTop } from '../utils';
import { pick, getScrollTop, ComponentInstance } from '../utils';
import { isDate } from '../utils/validate/date';
import {
t,
@ -23,28 +23,33 @@ import { useRefs } from '../composables/use-refs';
import { useExpose } from '../composables/use-expose';
// Components
import Popup from '../popup';
import Popup, { PopupPosition } from '../popup';
import Button from '../button';
import Toast from '../toast';
import Month from './components/Month';
import Month, { CalendarType } from './components/Month';
import Header from './components/Header';
// Types
import type { DayItem } from './components/Day';
export default createComponent({
props: {
show: Boolean,
title: String,
color: String,
readonly: Boolean,
teleport: [String, Object],
formatter: Function,
teleport: [String, Object] as PropType<TeleportProps['to']>,
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<CalendarType>,
default: 'single',
},
round: {
@ -52,7 +57,7 @@ export default createComponent({
default: true,
},
position: {
type: String,
type: String as PropType<PopupPosition>,
default: 'bottom',
},
poppable: {
@ -96,14 +101,14 @@ export default createComponent({
default: true,
},
minDate: {
type: Date,
type: Date as PropType<Date>,
validator: isDate,
default: () => new Date(),
},
maxDate: {
type: Date,
type: Date as PropType<Date>,
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<ComponentInstance>();
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 selected = state.currentDate.some(
(dateItem: Date, index: number) => {
const equal = compareDay(dateItem, date) === 0;
if (equal) {
selectedIndex = index;
}
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 (
<Month