diff --git a/internal/build/src/type-unsafe-stricter.json b/internal/build/src/type-unsafe-stricter.json index ecbaf2bb6f..8c37672293 100644 --- a/internal/build/src/type-unsafe-stricter.json +++ b/internal/build/src/type-unsafe-stricter.json @@ -5,7 +5,6 @@ "packages/components/col/", "packages/components/collapse-transition/", "packages/components/color-picker/", - "packages/components/date-picker/", "packages/components/descriptions/", "packages/components/dialog/", "packages/components/drawer/", @@ -39,7 +38,6 @@ "packages/components/table-v2/", "packages/components/table/", "packages/components/tabs/", - "packages/components/time-picker/", "packages/components/time-select/", "packages/components/timeline-item/", "packages/components/timeline/", diff --git a/packages/components/time-picker/src/common/picker.vue b/packages/components/time-picker/src/common/picker.vue index dee364772b..6c710191de 100644 --- a/packages/components/time-picker/src/common/picker.vue +++ b/packages/components/time-picker/src/common/picker.vue @@ -356,7 +356,9 @@ const handleFocusInput = (e?: FocusEvent) => { emit('focus', e) } -let currentHandleBlurDeferCallback: () => Promise | undefined +let currentHandleBlurDeferCallback: + | (() => Promise | undefined) + | undefined = undefined // Check if document.activeElement is inside popper or any input before popper close const handleBlurInput = (e?: FocusEvent) => { diff --git a/packages/components/time-picker/src/common/props.ts b/packages/components/time-picker/src/common/props.ts index 0500f926b7..4aecd69530 100644 --- a/packages/components/time-picker/src/common/props.ts +++ b/packages/components/time-picker/src/common/props.ts @@ -1,6 +1,7 @@ import { buildProps, definePropType } from '@element-plus/utils' import { useSizeProp } from '@element-plus/hooks' import { CircleClose } from '@element-plus/icons-vue' +import { disabledTimeListsProps } from '../props/shared' import type { Component, ExtractPropTypes } from 'vue' import type { Options } from '@popperjs/core' @@ -12,6 +13,18 @@ export type ModelValueType = SingleOrRange export type DayOrDays = SingleOrRange export type DateOrDates = SingleOrRange export type UserInput = SingleOrRange +export type GetDisabledHours = (role: string, comparingDate?: Dayjs) => number[] +export type GetDisabledMinutes = ( + hour: number, + role: string, + comparingDate?: Dayjs +) => number[] +export type GetDisabledSeconds = ( + hour: number, + minute: number, + role: string, + comparingDate?: Dayjs +) => number[] export const timePickerDefaultProps = buildProps({ id: { @@ -84,15 +97,7 @@ export const timePickerDefaultProps = buildProps({ type: Boolean, default: false, }, - disabledHours: { - type: Function, - }, - disabledMinutes: { - type: Function, - }, - disabledSeconds: { - type: Function, - }, + ...disabledTimeListsProps, disabledDate: { type: Function, }, diff --git a/packages/components/time-picker/src/composables/use-time-panel.ts b/packages/components/time-picker/src/composables/use-time-panel.ts index 41142dba95..4f57090595 100644 --- a/packages/components/time-picker/src/composables/use-time-panel.ts +++ b/packages/components/time-picker/src/composables/use-time-panel.ts @@ -1,14 +1,15 @@ import type { Dayjs } from 'dayjs' +import type { + GetDisabledHoursState, + GetDisabledMinutesState, + GetDisabledSecondsState, +} from '../types' + type UseTimePanelProps = { - getAvailableHours: (role: string, compare?: Dayjs) => number[] - getAvailableMinutes: (hour: number, role: string, compare?: Dayjs) => number[] - getAvailableSeconds: ( - hour: number, - minute: number, - role: string, - compare?: Dayjs - ) => number[] + getAvailableHours: GetDisabledHoursState + getAvailableMinutes: GetDisabledMinutesState + getAvailableSeconds: GetDisabledSecondsState } export const useTimePanel = ({ @@ -30,7 +31,7 @@ export const useTimePanel = ({ let result = date ;(['hour', 'minute', 'second'] as const).forEach((type) => { if (availableTimeGetters[type]) { - let availableTimeSlots + let availableTimeSlots: number[] const method = availableTimeGetters[type] switch (type) { case 'minute': { diff --git a/packages/components/time-picker/src/composables/use-time-picker.ts b/packages/components/time-picker/src/composables/use-time-picker.ts new file mode 100644 index 0000000000..f279e1ba19 --- /dev/null +++ b/packages/components/time-picker/src/composables/use-time-picker.ts @@ -0,0 +1,116 @@ +import { ref, watch } from 'vue' +import { makeList } from '../utils' + +import type { Dayjs } from 'dayjs' +import type { + GetDisabledHoursState, + GetDisabledMinutesState, + GetDisabledSecondsState, +} from '../types' +import type { + GetDisabledHours, + GetDisabledMinutes, + GetDisabledSeconds, +} from '../props/shared' + +const makeAvailableArr = (disabledList: boolean[]): number[] => { + const trueOrNumber = (isDisabled: boolean, index: number) => + isDisabled || index + + const getNumber = (predicate: number | true): predicate is number => + predicate !== true + + return disabledList.map(trueOrNumber).filter(getNumber) +} + +export const getTimeLists = ( + disabledHours?: GetDisabledHours, + disabledMinutes?: GetDisabledMinutes, + disabledSeconds?: GetDisabledSeconds +) => { + const getHoursList = (role: string, compare?: Dayjs) => { + return makeList(24, disabledHours && (() => disabledHours?.(role, compare))) + } + + const getMinutesList = (hour: number, role: string, compare?: Dayjs) => { + return makeList( + 60, + disabledMinutes && (() => disabledMinutes?.(hour, role, compare)) + ) + } + + const getSecondsList = ( + hour: number, + minute: number, + role: string, + compare?: Dayjs + ) => { + return makeList( + 60, + disabledSeconds && (() => disabledSeconds?.(hour, minute, role, compare)) + ) + } + + return { + getHoursList, + getMinutesList, + getSecondsList, + } +} + +export const buildAvailableTimeSlotGetter = ( + disabledHours: GetDisabledHours, + disabledMinutes: GetDisabledMinutes, + disabledSeconds: GetDisabledSeconds +) => { + const { getHoursList, getMinutesList, getSecondsList } = getTimeLists( + disabledHours, + disabledMinutes, + disabledSeconds + ) + + const getAvailableHours: GetDisabledHoursState = (role, compare?) => { + return makeAvailableArr(getHoursList(role, compare)) + } + + const getAvailableMinutes: GetDisabledMinutesState = ( + hour, + role, + compare? + ) => { + return makeAvailableArr(getMinutesList(hour, role, compare)) + } + + const getAvailableSeconds: GetDisabledSecondsState = ( + hour, + minute, + role, + compare? + ) => { + return makeAvailableArr(getSecondsList(hour, minute, role, compare)) + } + + return { + getAvailableHours, + getAvailableMinutes, + getAvailableSeconds, + } +} + +export const useOldValue = (props: { + parsedValue?: string | Dayjs | Dayjs[] + visible: boolean +}) => { + const oldValue = ref(props.parsedValue) + + watch( + () => props.visible, + (val) => { + if (!val) { + oldValue.value = props.parsedValue + } + } + ) + + return oldValue +} diff --git a/packages/components/time-picker/src/props/basic-time-spinner.ts b/packages/components/time-picker/src/props/basic-time-spinner.ts index ee2f22428c..a0791b2272 100644 --- a/packages/components/time-picker/src/props/basic-time-spinner.ts +++ b/packages/components/time-picker/src/props/basic-time-spinner.ts @@ -1,4 +1,5 @@ import { buildProps, definePropType } from '@element-plus/utils' +import { disabledTimeListsProps } from '../props/shared' import type { ExtractPropTypes } from 'vue' import type { Dayjs } from 'dayjs' @@ -22,26 +23,7 @@ export const basicTimeSpinnerProps = buildProps({ type: definePropType<'a' | 'A' | ''>(String), default: '', }, - disabledHours: { - type: definePropType<(role: string, comparingDate?: Dayjs) => number[]>( - Function - ), - }, - disabledMinutes: { - type: definePropType< - (hour: number, role: string, comparingDate?: Dayjs) => number[] - >(Function), - }, - disabledSeconds: { - type: definePropType< - ( - hour: number, - minute: number, - role: string, - comparingDate?: Dayjs - ) => number[] - >(Function), - }, + ...disabledTimeListsProps, } as const) export type BasicTimeSpinnerProps = ExtractPropTypes< diff --git a/packages/components/time-picker/src/props/panel-time-picker.ts b/packages/components/time-picker/src/props/panel-time-picker.ts index dca783d8b9..418a21b6f6 100644 --- a/packages/components/time-picker/src/props/panel-time-picker.ts +++ b/packages/components/time-picker/src/props/panel-time-picker.ts @@ -1,22 +1,15 @@ import { buildProps, definePropType } from '@element-plus/utils' +import { timePanelSharedProps } from './shared' import type { ExtractPropTypes } from 'vue' import type { Dayjs } from 'dayjs' export const panelTimePickerProps = buildProps({ - visible: Boolean, - actualVisible: { - type: Boolean, - default: undefined, - }, + ...timePanelSharedProps, datetimeRole: String, parsedValue: { type: definePropType(Object), }, - format: { - type: String, - default: '', - }, } as const) export type PanelTimePickerProps = ExtractPropTypes diff --git a/packages/components/time-picker/src/props/panel-time-range.ts b/packages/components/time-picker/src/props/panel-time-range.ts index d4839bb033..c205029e3f 100644 --- a/packages/components/time-picker/src/props/panel-time-range.ts +++ b/packages/components/time-picker/src/props/panel-time-range.ts @@ -1,18 +1,14 @@ import { buildProps, definePropType } from '@element-plus/utils' +import { timePanelSharedProps } from './shared' import type { ExtractPropTypes } from 'vue' import type { Dayjs } from 'dayjs' export const panelTimeRangeProps = buildProps({ - visible: Boolean, - actualVisible: Boolean, + ...timePanelSharedProps, parsedValue: { type: definePropType<[Dayjs, Dayjs]>(Array), }, - format: { - type: String, - default: '', - }, } as const) export type PanelTimeRangeProps = ExtractPropTypes diff --git a/packages/components/time-picker/src/props/shared.ts b/packages/components/time-picker/src/props/shared.ts new file mode 100644 index 0000000000..626e1c8a45 --- /dev/null +++ b/packages/components/time-picker/src/props/shared.ts @@ -0,0 +1,47 @@ +import { buildProps, definePropType } from '@element-plus/utils' + +import type { ExtractPropTypes } from 'vue' +import type { Dayjs } from 'dayjs' + +export type GetDisabledHours = (role: string, comparingDate?: Dayjs) => number[] +export type GetDisabledMinutes = ( + hour: number, + role: string, + comparingDate?: Dayjs +) => number[] +export type GetDisabledSeconds = ( + hour: number, + minute: number, + role: string, + comparingDate?: Dayjs +) => number[] + +export const disabledTimeListsProps = buildProps({ + disabledHours: { + type: definePropType(Function), + }, + disabledMinutes: { + type: definePropType(Function), + }, + disabledSeconds: { + type: definePropType(Function), + }, +} as const) + +export type DisabledTimeListsProps = ExtractPropTypes< + typeof disabledTimeListsProps +> + +export const timePanelSharedProps = buildProps({ + visible: Boolean, + actualVisible: { + type: Boolean, + default: undefined, + }, + format: { + type: String, + default: '', + }, +} as const) + +export type TimePanelSharedProps = ExtractPropTypes diff --git a/packages/components/time-picker/src/time-picker-com/basic-time-spinner.vue b/packages/components/time-picker/src/time-picker-com/basic-time-spinner.vue index afbfba637b..806ecc2f15 100644 --- a/packages/components/time-picker/src/time-picker-com/basic-time-spinner.vue +++ b/packages/components/time-picker/src/time-picker-com/basic-time-spinner.vue @@ -88,7 +88,7 @@ import { useNamespace } from '@element-plus/hooks' import { timeUnits } from '../constants' import { buildTimeList } from '../utils' import { basicTimeSpinnerProps } from '../props/basic-time-spinner' -import { getTimeLists } from './useTimePicker' +import { getTimeLists } from '../composables/use-time-picker' import type { Ref } from 'vue' import type { ScrollbarInstance } from '@element-plus/components/scrollbar' diff --git a/packages/components/time-picker/src/time-picker-com/panel-time-pick.vue b/packages/components/time-picker/src/time-picker-com/panel-time-pick.vue index 0578dd5b67..28efa389ed 100644 --- a/packages/components/time-picker/src/time-picker-com/panel-time-pick.vue +++ b/packages/components/time-picker/src/time-picker-com/panel-time-pick.vue @@ -45,8 +45,11 @@ import { useLocale, useNamespace } from '@element-plus/hooks' import { isUndefined } from '@element-plus/utils' import { panelTimePickerProps } from '../props/panel-time-picker' import { useTimePanel } from '../composables/use-time-panel' +import { + buildAvailableTimeSlotGetter, + useOldValue, +} from '../composables/use-time-picker' import TimeSpinner from './basic-time-spinner.vue' -import { getAvailableArrs, useOldValue } from './useTimePicker' import type { Dayjs } from 'dayjs' @@ -63,7 +66,7 @@ const { defaultValue, } = pickerBase.props const { getAvailableHours, getAvailableMinutes, getAvailableSeconds } = - getAvailableArrs(disabledHours, disabledMinutes, disabledSeconds) + buildAvailableTimeSlotGetter(disabledHours, disabledMinutes, disabledSeconds) const ns = useNamespace('time') const { t, lang } = useLocale() diff --git a/packages/components/time-picker/src/time-picker-com/panel-time-range.vue b/packages/components/time-picker/src/time-picker-com/panel-time-range.vue index dd2e109a1e..21d275ecbb 100644 --- a/packages/components/time-picker/src/time-picker-com/panel-time-range.vue +++ b/packages/components/time-picker/src/time-picker-com/panel-time-range.vue @@ -90,8 +90,11 @@ import { isArray } from '@element-plus/utils' import { EVENT_CODE } from '@element-plus/constants' import { panelTimeRangeProps } from '../props/panel-time-range' import { useTimePanel } from '../composables/use-time-panel' +import { + buildAvailableTimeSlotGetter, + useOldValue, +} from '../composables/use-time-picker' import TimeSpinner from './basic-time-spinner.vue' -import { getAvailableArrs, useOldValue } from './useTimePicker' import type { Dayjs } from 'dayjs' @@ -99,7 +102,7 @@ const props = defineProps(panelTimeRangeProps) const emit = defineEmits(['pick', 'select-range', 'set-picker-option']) const makeSelectRange = (start: number, end: number) => { - const result = [] + const result: number[] = [] for (let i = start; i <= end; i++) { result.push(i) } @@ -262,7 +265,11 @@ const getRangeAvailableTime = ([start, end]: Array) => { } const { getAvailableHours, getAvailableMinutes, getAvailableSeconds } = - getAvailableArrs(disabledHours_, disabledMinutes_, disabledSeconds_) + buildAvailableTimeSlotGetter( + disabledHours_, + disabledMinutes_, + disabledSeconds_ + ) const { timePickerOptions, diff --git a/packages/components/time-picker/src/time-picker-com/useTimePicker.ts b/packages/components/time-picker/src/time-picker-com/useTimePicker.ts deleted file mode 100644 index 053c2891bf..0000000000 --- a/packages/components/time-picker/src/time-picker-com/useTimePicker.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { ref, watch } from 'vue' - -import type { Dayjs } from 'dayjs' - -const makeList = (total, method, methodFunc) => { - const arr = [] - const disabledArr = method && methodFunc() - for (let i = 0; i < total; i++) { - arr[i] = disabledArr ? disabledArr.includes(i) : false - } - return arr -} - -const makeAvailableArr = (list) => { - return list.map((_, index) => (!_ ? index : _)).filter((_) => _ !== true) -} - -export const getTimeLists = ( - disabledHours, - disabledMinutes, - disabledSeconds -) => { - const getHoursList = (role, compare?) => { - return makeList(24, disabledHours, () => disabledHours(role, compare)) - } - - const getMinutesList = (hour, role, compare?) => { - return makeList(60, disabledMinutes, () => - disabledMinutes(hour, role, compare) - ) - } - - const getSecondsList = (hour, minute, role, compare?) => { - return makeList(60, disabledSeconds, () => - disabledSeconds(hour, minute, role, compare) - ) - } - - return { - getHoursList, - getMinutesList, - getSecondsList, - } -} - -export const getAvailableArrs = ( - disabledHours, - disabledMinutes, - disabledSeconds -) => { - const { getHoursList, getMinutesList, getSecondsList } = getTimeLists( - disabledHours, - disabledMinutes, - disabledSeconds - ) - - const getAvailableHours = (role, compare?) => { - return makeAvailableArr(getHoursList(role, compare)) - } - - const getAvailableMinutes = (hour, role, compare?) => { - return makeAvailableArr(getMinutesList(hour, role, compare)) - } - - const getAvailableSeconds = (hour, minute, role, compare?) => { - return makeAvailableArr(getSecondsList(hour, minute, role, compare)) - } - - return { - getAvailableHours, - getAvailableMinutes, - getAvailableSeconds, - } -} - -export const useOldValue = (props: { - parsedValue?: string | Dayjs | Dayjs[] - visible: boolean -}) => { - const oldValue = ref(props.parsedValue) - - watch( - () => props.visible, - (val) => { - if (!val) { - oldValue.value = props.parsedValue - } - } - ) - - return oldValue -} diff --git a/packages/components/time-picker/src/types.ts b/packages/components/time-picker/src/types.ts new file mode 100644 index 0000000000..7b89ea33a1 --- /dev/null +++ b/packages/components/time-picker/src/types.ts @@ -0,0 +1,19 @@ +import type { Dayjs } from 'dayjs' + +export type GetDisabledHoursState = ( + role: string, + comparingDate?: Dayjs +) => number[] + +export type GetDisabledMinutesState = ( + hour: number, + role: string, + comparingDate?: Dayjs +) => number[] + +export type GetDisabledSecondsState = ( + hour: number, + minute: number, + role: string, + comparingDate?: Dayjs +) => number[] diff --git a/packages/components/time-picker/src/utils.ts b/packages/components/time-picker/src/utils.ts index 0642a89b3f..0a8b86b563 100644 --- a/packages/components/time-picker/src/utils.ts +++ b/packages/components/time-picker/src/utils.ts @@ -28,7 +28,7 @@ export const extractTimeFormat = (format: string) => { .trim() } -export const dateEquals = function (a: Date | any, b: Date | any) { +export const dateEquals = function (a: Date | unknown, b: Date | unknown) { const aIsDate = isDate(a) const bIsDate = isDate(b) if (aIsDate && bIsDate) { @@ -79,3 +79,12 @@ export const formatter = function ( if (format === 'x') return +date return dayjs(date).locale(lang).format(format) } + +export const makeList = (total: number, method?: () => number[]) => { + const arr: boolean[] = [] + const disabledArr = method?.() + for (let i = 0; i < total; i++) { + arr.push(disabledArr?.includes(i) ?? false) + } + return arr +}