mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
types(Calendar): use tsx (#8180)
This commit is contained in:
parent
8696f4ee70
commit
d092d669f2
@ -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_ | 当前日期 |
|
||||
|
@ -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()}
|
@ -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}
|
@ -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 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 (
|
||||
<Month
|
Loading…
x
Reference in New Issue
Block a user