diff --git a/src/datetime-picker/DatePicker.js b/src/datetime-picker/DatePicker.tsx similarity index 87% rename from src/datetime-picker/DatePicker.js rename to src/datetime-picker/DatePicker.tsx index c412dea47..4b07091bd 100644 --- a/src/datetime-picker/DatePicker.js +++ b/src/datetime-picker/DatePicker.tsx @@ -1,15 +1,23 @@ -import { ref, watch, computed, nextTick, onMounted } from 'vue'; +import { ref, watch, computed, nextTick, onMounted, PropType } from 'vue'; // Utils import { isDate } from '../utils/validate/date'; -import { pick, padZero, createNamespace } from '../utils'; -import { times, sharedProps, getTrueValue, getMonthEndDay } from './utils'; +import { pick, range, padZero, createNamespace } from '../utils'; +import { + times, + ColumnType, + pickerKeys, + sharedProps, + getTrueValue, + getMonthEndDay, + DatetimePickerType, +} from './utils'; // Composition import { useExpose } from '../composables/use-expose'; // Components -import Picker, { pickerProps } from '../picker'; +import Picker from '../picker'; const currentYear = new Date().getFullYear(); const [createComponent] = createNamespace('date-picker'); @@ -17,17 +25,18 @@ const [createComponent] = createNamespace('date-picker'); export default createComponent({ props: { ...sharedProps, + modelValue: Date as PropType, type: { - type: String, + type: String as PropType, default: 'datetime', }, minDate: { - type: Date, + type: Date as PropType, default: () => new Date(currentYear - 10, 0, 1), validator: isDate, }, maxDate: { - type: Date, + type: Date as PropType, default: () => new Date(currentYear + 10, 11, 31), validator: isDate, }, @@ -36,22 +45,23 @@ export default createComponent({ emits: ['confirm', 'cancel', 'change', 'update:modelValue'], setup(props, { emit, slots }) { - const formatValue = (value) => { - if (!isDate(value)) { - value = props.minDate; + const formatValue = (value?: Date) => { + if (isDate(value)) { + const timestamp = range( + value.getTime(), + props.minDate.getTime(), + props.maxDate.getTime() + ); + return new Date(timestamp); } - - value = Math.max(value, props.minDate.getTime()); - value = Math.min(value, props.maxDate.getTime()); - - return new Date(value); + return props.minDate; }; const picker = ref(); const currentDate = ref(formatValue(props.modelValue)); - const getBoundary = (type, value) => { - const boundary = props[`${type}Date`]; + const getBoundary = (type: 'max' | 'min', value: Date) => { + const boundary = props[`${type}Date` as const]; const year = boundary.getFullYear(); let month = 1; let date = 1; @@ -98,7 +108,7 @@ export default createComponent({ currentDate.value ); - let result = [ + let result: Array<{ type: ColumnType; range: number[] }> = [ { type: 'year', range: [minYear, maxYear], @@ -205,7 +215,7 @@ export default createComponent({ const { type } = props; const indexes = picker.value.getIndexes(); - const getValue = (type) => { + const getValue = (type: ColumnType) => { let index = 0; originColumns.value.forEach((column, columnIndex) => { if (type === column.type) { @@ -301,11 +311,10 @@ export default createComponent({ v-slots={slots} ref={picker} columns={columns.value} - readonly={props.readonly} onChange={onChange} onCancel={onCancel} onConfirm={onConfirm} - {...pick(props, Object.keys(pickerProps))} + {...pick(props, pickerKeys)} /> ); }, diff --git a/src/datetime-picker/README.md b/src/datetime-picker/README.md index 7a3f7e738..0c5f0b65a 100644 --- a/src/datetime-picker/README.md +++ b/src/datetime-picker/README.md @@ -284,8 +284,8 @@ export default { | show-toolbar | Whether to show toolbar | _boolean_ | `true` | | loading | Whether to show loading prompt | _boolean_ | `false` | | readonly | Whether to be readonly | _boolean_ | `false` | -| filter | Option filter | _(type, vals) => vals_ | - | -| formatter | Option text formatter | _(type, val) => val_ | - | +| filter | Option filter | _(type: string, values: string[]) => string[]_ | - | +| formatter | Option text formatter | _(type: string, value: string) => string_ | - | | columns-order | Array for ordering columns, where item can be set to
`year`, `month`, `day`, `hour` and `minute` | _string[]_ | - | | item-height | Option height, supports `px` `vw` `vh` `rem` unit, default `px` | _number \| string_ | `44` | | visible-item-count | Count of visible columns | _number \| string_ | `6` | diff --git a/src/datetime-picker/README.zh-CN.md b/src/datetime-picker/README.zh-CN.md index 345e7e046..27ebfbe0d 100644 --- a/src/datetime-picker/README.zh-CN.md +++ b/src/datetime-picker/README.zh-CN.md @@ -293,8 +293,8 @@ export default { | show-toolbar | 是否显示顶部栏 | _boolean_ | `true` | | loading | 是否显示加载状态 | _boolean_ | `false` | | readonly | 是否为只读状态,只读状态下无法切换选项 | _boolean_ | `false` | -| filter | 选项过滤函数 | _(type, vals) => vals_ | - | -| formatter | 选项格式化函数 | _(type, val) => val_ | - | +| filter | 选项过滤函数 | _(type: string, values: string[]) => string[]_ | - | +| formatter | 选项格式化函数 | _(type: string, value: string) => string_ | - | | columns-order | 自定义列排序数组, 子项可选值为
`year`、`month`、`day`、`hour`、`minute` | _string[]_ | - | | item-height | 选项高度,支持 `px` `vw` `vh` `rem` 单位,默认 `px` | _number \| string_ | `44` | | visible-item-count | 可见的选项个数 | _number \| string_ | `6` | diff --git a/src/datetime-picker/TimePicker.js b/src/datetime-picker/TimePicker.tsx similarity index 86% rename from src/datetime-picker/TimePicker.js rename to src/datetime-picker/TimePicker.tsx index 5e8fc9ac2..880b8e9a2 100644 --- a/src/datetime-picker/TimePicker.js +++ b/src/datetime-picker/TimePicker.tsx @@ -1,20 +1,27 @@ import { ref, watch, computed, nextTick, onMounted } from 'vue'; // Utils -import { pick, range, padZero, createNamespace } from '../utils'; -import { times, sharedProps } from './utils'; +import { + pick, + range, + padZero, + createNamespace, + ComponentInstance, +} from '../utils'; +import { times, sharedProps, pickerKeys } from './utils'; // Composition import { useExpose } from '../composables/use-expose'; // Components -import Picker, { pickerProps } from '../picker'; +import Picker from '../picker'; const [createComponent] = createNamespace('time-picker'); export default createComponent({ props: { ...sharedProps, + modelValue: String, minHour: { type: [Number, String], default: 0, @@ -36,7 +43,7 @@ export default createComponent({ emits: ['confirm', 'cancel', 'change', 'update:modelValue'], setup(props, { emit, slots }) { - const formatValue = (value) => { + const formatValue = (value?: string) => { const { minHour, maxHour, maxMinute, minMinute } = props; if (!value) { @@ -44,13 +51,13 @@ export default createComponent({ } let [hour, minute] = value.split(':'); - hour = padZero(range(hour, minHour, maxHour)); - minute = padZero(range(minute, minMinute, maxMinute)); + hour = padZero(range(+hour, +minHour, +maxHour)); + minute = padZero(range(+minute, +minMinute, +maxMinute)); return `${hour}:${minute}`; }; - const picker = ref(); + const picker = ref(); const currentDate = ref(formatValue(props.modelValue)); const ranges = computed(() => [ @@ -97,12 +104,12 @@ export default createComponent({ ]; nextTick(() => { - picker.value.setValues(values); + picker.value!.setValues(values); }); }; const updateInnerValue = () => { - const [hourIndex, minuteIndex] = picker.value.getIndexes(); + const [hourIndex, minuteIndex] = picker.value!.getIndexes(); const [hourColumn, minuteColumn] = originColumns.value; const hour = hourColumn.values[hourIndex] || hourColumn.values[0]; @@ -173,11 +180,10 @@ export default createComponent({ v-slots={slots} ref={picker} columns={columns.value} - readonly={props.readonly} onChange={onChange} onCancel={onCancel} onConfirm={onConfirm} - {...pick(props, Object.keys(pickerProps))} + {...pick(props, pickerKeys)} /> ); }, diff --git a/src/datetime-picker/index.js b/src/datetime-picker/index.tsx similarity index 87% rename from src/datetime-picker/index.js rename to src/datetime-picker/index.tsx index fac3a4136..9164633d0 100644 --- a/src/datetime-picker/index.js +++ b/src/datetime-picker/index.tsx @@ -1,5 +1,5 @@ import { ref } from 'vue'; -import { pick, createNamespace } from '../utils'; +import { pick, createNamespace, ComponentInstance } from '../utils'; import { useExpose } from '../composables/use-expose'; import TimePicker from './TimePicker'; import DatePicker from './DatePicker'; @@ -13,10 +13,11 @@ export default createComponent({ props: { ...TimePicker.props, ...DatePicker.props, + modelValue: [String, Date], }, setup(props, { attrs, slots }) { - const root = ref(); + const root = ref(); useExpose({ getPicker: () => root.value?.getPicker(), diff --git a/src/datetime-picker/utils.ts b/src/datetime-picker/utils.ts index 623d296a3..3500d7b88 100644 --- a/src/datetime-picker/utils.ts +++ b/src/datetime-picker/utils.ts @@ -1,20 +1,34 @@ +import { PropType } from 'vue'; import { isNaN } from '../utils/validate/number'; import { pickerProps } from '../picker'; +export type ColumnType = 'year' | 'month' | 'day' | 'hour' | 'minute'; + +export type DatetimePickerType = + | 'date' + | 'time' + | 'datetime' + | 'datehour' + | 'month-day' + | 'year-month'; + export const sharedProps = { ...pickerProps, - filter: Function, - modelValue: null, - columnsOrder: Array, + filter: Function as PropType<(type: string, values: string[]) => string[]>, + columnsOrder: Array as PropType, formatter: { - type: Function, - default: (type: string, value: unknown) => value, + type: Function as PropType<(type: string, value: string) => string>, + default: (type: string, value: string) => value, }, }; -export function times(n: number, iteratee: (index: number) => any[]) { +export const pickerKeys = Object.keys(pickerProps) as Array< + keyof typeof pickerProps +>; + +export function times(n: number, iteratee: (index: number) => T) { let index = -1; - const result = Array(n); + const result: T[] = Array(n); while (++index < n) { result[index] = iteratee(index); diff --git a/src/utils/validate/date.ts b/src/utils/validate/date.ts index d06fd6696..d62b3c9c3 100644 --- a/src/utils/validate/date.ts +++ b/src/utils/validate/date.ts @@ -1,8 +1,8 @@ import { isNaN } from './number'; -export function isDate(val: Date): val is Date { +export function isDate(val: unknown): val is Date { return ( Object.prototype.toString.call(val) === '[object Date]' && - !isNaN(val.getTime()) + !isNaN((val as Date).getTime()) ); }