mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
Refactor/time picker refactor to setup (#8191)
* chore: refine code * chore(build): [time/date-picker] type unsafe * Remove `time/date-picker` entry from typing list. * refactor(components): [time-picker] utilities * Refine typing for utilities. * Extract common props. * chore: fix typing * chore: fix typing * chore: refine code Co-authored-by: JeremyWuuuuu <15975785+JeremyWuuuuu@users.noreply.github.com>
This commit is contained in:
@@ -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/",
|
||||
|
||||
@@ -356,7 +356,9 @@ const handleFocusInput = (e?: FocusEvent) => {
|
||||
emit('focus', e)
|
||||
}
|
||||
|
||||
let currentHandleBlurDeferCallback: () => Promise<void> | undefined
|
||||
let currentHandleBlurDeferCallback:
|
||||
| (() => Promise<void> | undefined)
|
||||
| undefined = undefined
|
||||
|
||||
// Check if document.activeElement is inside popper or any input before popper close
|
||||
const handleBlurInput = (e?: FocusEvent) => {
|
||||
|
||||
@@ -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<DateModelType>
|
||||
export type DayOrDays = SingleOrRange<Dayjs>
|
||||
export type DateOrDates = SingleOrRange<Date>
|
||||
export type UserInput = SingleOrRange<string | null>
|
||||
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,
|
||||
},
|
||||
|
||||
@@ -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': {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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<
|
||||
|
||||
@@ -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<Dayjs>(Object),
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
} as const)
|
||||
|
||||
export type PanelTimePickerProps = ExtractPropTypes<typeof panelTimePickerProps>
|
||||
|
||||
@@ -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<typeof panelTimeRangeProps>
|
||||
|
||||
47
packages/components/time-picker/src/props/shared.ts
Normal file
47
packages/components/time-picker/src/props/shared.ts
Normal file
@@ -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<GetDisabledHours>(Function),
|
||||
},
|
||||
disabledMinutes: {
|
||||
type: definePropType<GetDisabledMinutes>(Function),
|
||||
},
|
||||
disabledSeconds: {
|
||||
type: definePropType<GetDisabledSeconds>(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<typeof timePanelSharedProps>
|
||||
@@ -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'
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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<Dayjs>) => {
|
||||
}
|
||||
|
||||
const { getAvailableHours, getAvailableMinutes, getAvailableSeconds } =
|
||||
getAvailableArrs(disabledHours_, disabledMinutes_, disabledSeconds_)
|
||||
buildAvailableTimeSlotGetter(
|
||||
disabledHours_,
|
||||
disabledMinutes_,
|
||||
disabledSeconds_
|
||||
)
|
||||
|
||||
const {
|
||||
timePickerOptions,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
19
packages/components/time-picker/src/types.ts
Normal file
19
packages/components/time-picker/src/types.ts
Normal file
@@ -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[]
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user