chore: date-picker-panel tweaks (#21827)

* docs(components): [date-picker-panel] add missing props & make the doc clearer

* fix(components): [date-picker-panel] set default time-format & date-format

* refactor(components): [date-picker-panel] remove `format` property
This commit is contained in:
Noblet Ouways
2025-08-21 14:01:27 +02:00
committed by GitHub
parent 96c5d8ae8c
commit a985f511a0
12 changed files with 114 additions and 64 deletions

View File

@@ -65,10 +65,11 @@ Note, date time locale (month name, first day of the week ...) are also configur
| disabled | whether DatePicker is disabled | ^[boolean] | false |
| clearable | whether to show clear button | ^[boolean] | true |
| type | type of the picker | ^[enum]`'year' \| 'years' \|'month' \| 'months' \| 'date' \| 'dates' \| 'datetime' \| 'week' \| 'datetimerange' \| 'daterange' \| 'monthrange' \| 'yearrange'` | date |
| format | format of the displayed value in the input box (in datetime/datetimerange mode) | ^[string] | YYYY-MM-DD |
| default-value | optional, default date of the calendar | ^[object]`Date \| [Date, Date]` | — |
| default-time | optional, the time value to use when selecting date range | ^[object]`Date \| [Date, Date]` | — |
| value-format | optional, format of binding value. If not specified, the binding value will be a Date object | ^[string] | — |
| date-format | optional, format of the date displayed in input's inner panel | ^[string] see [date formats](https://day.js.org/docs/en/display/format) | YYYY-MM-DD |
| time-format | optional, format of the time displayed in input's inner panel | ^[string] see [date formats](https://day.js.org/docs/en/display/format) | HH:mm:ss |
| unlink-panels | unlink two date-panels in range-picker | ^[boolean] | false |
| disabled-date | a function determining if a date is disabled with that date as its parameter. Should return a Boolean | ^[Function]`(data: Date) => boolean` | — |
| shortcuts | an object array to set shortcut options | ^[object]`Array<{ text: string, value: Date \| Function }>` | [] |

View File

@@ -99,8 +99,8 @@ datetime-picker/custom-icon
| default-value | optional, default date of the calendar | ^[object]`Date \| [Date, Date]` | — |
| default-time | the default time value after picking a date. Time `00:00:00` will be used if not specified | ^[object]`Date \| [Date, Date]` | — |
| value-format | optional, format of binding value. If not specified, the binding value will be a Date object | ^[string] see [date formats](https://day.js.org/docs/en/display/format) | — |
| date-format ^(2.4.0) | optional, format of the date displayed value in TimePicker's dropdown | ^[string] see [date formats](https://day.js.org/docs/en/display/format) | |
| time-format ^(2.4.0) | optional, format of the time displayed value in TimePicker's dropdown | ^[string] see [date formats](https://day.js.org/docs/en/display/format) | |
| date-format ^(2.4.0) | optional, format of the date displayed in input's inner panel | ^[string] see [date formats](https://day.js.org/docs/en/display/format) | YYYY-MM-DD |
| time-format ^(2.4.0) | optional, format of the time displayed in input's inner panel | ^[string] see [date formats](https://day.js.org/docs/en/display/format) | HH:mm:ss |
| id | same as `id` in native input | ^[string] / ^[object]`[string, string]` | — |
| name | same as `name` in native input | ^[string] | — |
| unlink-panels | unlink two date-panels in range-picker | ^[boolean] | false |

View File

@@ -105,16 +105,14 @@ describe('DatePickerPanel', () => {
describe(':type="datetime" & :type="datetimerange"', () => {
describe(':type="datetime"', () => {
it('both picker show correct formated value (extract date-format and time-format from format property', async () => {
it('dateFormat & timeFormat', async () => {
const value = ref(new Date(2018, 2, 5, 10, 15, 24))
const format = ref('YYYY/MM/DD HH:mm A')
const dateFormat = ref('')
const timeFormat = ref('')
const dateFormat = ref('YYYY/MM/DD')
const timeFormat = ref('HH:mm A')
const wrapper = mount(() => (
<DatePickerPanel
v-model={value.value}
type="datetime"
format={format.value}
dateFormat={dateFormat.value}
timeFormat={timeFormat.value}
/>
@@ -132,7 +130,8 @@ describe('DatePickerPanel', () => {
expect(dateInput.value).toBe('2018/03/05')
expect(timeInput.value).toBe('10:15 AM')
format.value = 'MM-DD-YYYY HH a'
dateFormat.value = 'MM-DD-YYYY'
timeFormat.value = 'HH a'
await nextTick()
expect(dateInput.value).toBe('03-05-2018')
expect(timeInput.value).toBe('10 am')
@@ -470,14 +469,13 @@ describe('DatePickerPanel', () => {
new Date(2000, 10, 8, 10, 10),
new Date(2000, 10, 11, 10, 10),
])
const dateFormat = ref('')
const timeFormat = ref('')
const dateFormat = ref('YYYY/MM/DD')
const timeFormat = ref('HH:mm A')
const wrapper = mount(() => (
<DatePickerPanel
v-model={value.value}
type="datetimerange"
default-time={new Date(2020, 1, 1, 1, 1, 1)}
format="YYYY/MM/DD HH:mm A"
dateFormat={dateFormat.value}
timeFormat={timeFormat.value}
showFooter

View File

@@ -226,6 +226,8 @@ import { ClickOutside as vClickOutside } from '@element-plus/directives'
import { useLocale, useNamespace } from '@element-plus/hooks'
import ElInput from '@element-plus/components/input'
import {
DEFAULT_FORMATS_DATE,
DEFAULT_FORMATS_TIME,
PICKER_BASE_INJECTION_KEY,
TimePickPanel,
extractDateFormat,
@@ -276,7 +278,8 @@ const slots = useSlots()
const { t, lang } = useLocale()
const pickerBase = inject(PICKER_BASE_INJECTION_KEY) as any
const isDefaultFormat = inject(
ROOT_PICKER_IS_DEFAULT_FORMAT_INJECTION_KEY
ROOT_PICKER_IS_DEFAULT_FORMAT_INJECTION_KEY,
undefined
) as any
const { shortcuts, disabledDate, cellClassName, defaultTime } = pickerBase.props
const defaultValue = toRef(pickerBase.props, 'defaultValue')
@@ -576,11 +579,15 @@ const changeToNow = () => {
}
const timeFormat = computed(() => {
return props.timeFormat || extractTimeFormat(props.format)
return (
props.timeFormat || extractTimeFormat(props.format) || DEFAULT_FORMATS_TIME
)
})
const dateFormat = computed(() => {
return props.dateFormat || extractDateFormat(props.format)
return (
props.dateFormat || extractDateFormat(props.format) || DEFAULT_FORMATS_DATE
)
})
const visibleTime = computed(() => {

View File

@@ -406,6 +406,8 @@ import { useLocale } from '@element-plus/hooks'
import ElButton from '@element-plus/components/button'
import ElInput from '@element-plus/components/input'
import {
DEFAULT_FORMATS_DATE,
DEFAULT_FORMATS_TIME,
PICKER_BASE_INJECTION_KEY,
TimePickPanel,
extractDateFormat,
@@ -431,6 +433,7 @@ import YearTable from './basic-year-table.vue'
import MonthTable from './basic-month-table.vue'
import DateTable from './basic-date-table.vue'
import type { Ref } from 'vue'
import type { Dayjs } from 'dayjs'
type ChangeType = 'min' | 'max'
@@ -451,10 +454,11 @@ const unit = 'month'
// FIXME: fix the type for ep picker
const pickerBase = inject(PICKER_BASE_INJECTION_KEY) as any
const isDefaultFormat = inject(
ROOT_PICKER_IS_DEFAULT_FORMAT_INJECTION_KEY
ROOT_PICKER_IS_DEFAULT_FORMAT_INJECTION_KEY,
undefined
) as any
const { disabledDate, cellClassName, defaultTime, clearable } = pickerBase.props
const format = toRef(pickerBase.props, 'format')
const format: Ref<string | undefined> = toRef(pickerBase.props, 'format')
const shortcuts = toRef(pickerBase.props, 'shortcuts')
const defaultValue = toRef(pickerBase.props, 'defaultValue')
const { lang } = useLocale()
@@ -553,11 +557,19 @@ const maxVisibleTime = computed(() => {
})
const timeFormat = computed(() => {
return props.timeFormat || extractTimeFormat(format.value)
return (
props.timeFormat ||
extractTimeFormat(format.value || '') ||
DEFAULT_FORMATS_TIME
)
})
const dateFormat = computed(() => {
return props.dateFormat || extractDateFormat(format.value)
return (
props.dateFormat ||
extractDateFormat(format.value || '') ||
DEFAULT_FORMATS_DATE
)
})
const isValidValue = (date: [Dayjs, Dayjs]) => {
@@ -882,7 +894,7 @@ const formatToString = (value: Dayjs | Dayjs[]) => {
const parseUserInput = (value: Dayjs | Dayjs[]) => {
return correctlyParseUserInput(
value,
format.value,
format.value || '',
lang.value,
isDefaultFormat
)

View File

@@ -148,7 +148,8 @@ const unit = 'year'
const { lang } = useLocale()
const pickerBase = inject(PICKER_BASE_INJECTION_KEY) as any
const isDefaultFormat = inject(
ROOT_PICKER_IS_DEFAULT_FORMAT_INJECTION_KEY
ROOT_PICKER_IS_DEFAULT_FORMAT_INJECTION_KEY,
undefined
) as any
const { shortcuts, disabledDate } = pickerBase.props
const format = toRef(pickerBase.props, 'format')

View File

@@ -133,7 +133,8 @@ const { lang } = useLocale()
const leftDate = ref(dayjs().locale(lang.value))
const rightDate = ref(dayjs().locale(lang.value).add(step, unit))
const isDefaultFormat = inject(
ROOT_PICKER_IS_DEFAULT_FORMAT_INJECTION_KEY
ROOT_PICKER_IS_DEFAULT_FORMAT_INJECTION_KEY,
undefined
) as any
const pickerBase = inject(PICKER_BASE_INJECTION_KEY) as any
const { shortcuts, disabledDate } = pickerBase.props

View File

@@ -1,11 +1,4 @@
import {
computed,
defineComponent,
inject,
provide,
reactive,
toRefs,
} from 'vue'
import { defineComponent, inject, provide, reactive, toRefs } from 'vue'
import dayjs from 'dayjs'
import customParseFormat from 'dayjs/plugin/customParseFormat.js'
import advancedFormat from 'dayjs/plugin/advancedFormat.js'
@@ -16,8 +9,6 @@ import dayOfYear from 'dayjs/plugin/dayOfYear.js'
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter.js'
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore.js'
import {
DEFAULT_FORMATS_DATE,
DEFAULT_FORMATS_DATEPICKER,
PICKER_BASE_INJECTION_KEY,
ROOT_COMMON_PICKER_INJECTION_KEY,
} from '@element-plus/components/time-picker'
@@ -25,10 +16,7 @@ import { useNamespace } from '@element-plus/hooks'
import { isUndefined } from '@element-plus/utils'
import { UPDATE_MODEL_EVENT } from '@element-plus/constants'
import { datePickerPanelProps } from './props/date-picker-panel'
import {
ROOT_PICKER_INJECTION_KEY,
ROOT_PICKER_IS_DEFAULT_FORMAT_INJECTION_KEY,
} from './constants'
import { ROOT_PICKER_INJECTION_KEY } from './constants'
import { getPanel } from './panel-utils'
import { useCommonPicker } from '../../time-picker/src/composables/use-common-picker'
@@ -54,27 +42,10 @@ export default defineComponent({
],
setup(props, { slots, emit }) {
const ns = useNamespace('picker-panel')
const format = computed(
() =>
props.format ??
(DEFAULT_FORMATS_DATEPICKER[props.type] || DEFAULT_FORMATS_DATE)
)
const defaultFormatInjection = inject(
ROOT_PICKER_IS_DEFAULT_FORMAT_INJECTION_KEY,
undefined
)
if (isUndefined(defaultFormatInjection)) {
const isDefaultFormat = computed(() => {
return !props.format
})
provide(ROOT_PICKER_IS_DEFAULT_FORMAT_INJECTION_KEY, isDefaultFormat)
}
const pickerInjection = inject(PICKER_BASE_INJECTION_KEY, undefined)
if (isUndefined(pickerInjection)) {
const _props = reactive({
...toRefs(props),
format,
})
provide(PICKER_BASE_INJECTION_KEY, {
props: _props,
@@ -102,7 +73,6 @@ export default defineComponent({
return (
<Component
{...props}
format={format.value}
parsedValue={parsedValue.value}
onSet-picker-option={onSetPickerOption}
onCalendar-change={onCalendarChange}

View File

@@ -9,20 +9,16 @@ import type {
import type { DatePickerType } from '../types'
export const datePickerPanelProps = buildProps({
/**
* @description format of the displayed value in the input box (in datetime/datetimerange mode)
*/
format: String,
/**
* @description optional, format of binding value. If not specified, the binding value will be a Date object
*/
valueFormat: String,
/**
* @description optional, format of the date displayed value in TimePicker's dropdown
* @description optional, format of the date displayed in input's inner panel
*/
dateFormat: String,
/**
* @description optional, format of the time displayed value in TimePicker's dropdown
* @description optional, format of the time displayed in input's inner panel
*/
timeFormat: String,
/**

View File

@@ -208,7 +208,7 @@ export const correctlyParseUserInput = (
value: string | Dayjs | Dayjs[],
format: string,
lang: string,
defaultFormat: ComputedRef<boolean>
defaultFormat: ComputedRef<boolean> | undefined
): Dayjs | Dayjs[] => {
if (isArray(value)) {
return value.map(
@@ -216,7 +216,9 @@ export const correctlyParseUserInput = (
)
}
if (isString(value)) {
const dayjsValue = defaultFormat.value ? dayjs(value) : dayjs(value, format)
const dayjsValue = defaultFormat?.value
? dayjs(value)
: dayjs(value, format)
if (!dayjsValue.isValid()) {
// return directly if not valid
return dayjsValue

View File

@@ -131,6 +131,35 @@ describe('Datetime Picker', () => {
expect(dayjs(value.value).diff(dayjs()) < 10).toBeTruthy()
})
it("should date input respect the default format 'YYYY-MM-DD' when format with only time format is setted", async () => {
const modelValue = new Date(2000, 10, 10, 10, 10)
const wrapper = mount(() => (
<DatePicker v-model={modelValue} format="HH:mm:ss" type="datetime" />
))
const input = wrapper.find('input')
await input.trigger('blur')
await input.trigger('focus')
const timeInput = document.querySelector(
'.el-date-picker__editor-wrap input'
)
expect((timeInput as HTMLInputElement).value).toBe('2000-11-10')
})
it("should time input respect the default format 'HH:mm:ss' when format with only date format is setted", async () => {
const modelValue = new Date(2000, 10, 10, 10, 10)
const wrapper = mount(() => (
<DatePicker v-model={modelValue} format="YYYY" type="datetime" />
))
const input = wrapper.find('input')
await input.trigger('blur')
await input.trigger('focus')
const timeInput = document.querySelectorAll(
'.el-date-picker__editor-wrap input'
)[1]
expect((timeInput as HTMLInputElement).value).toBe('10:10:00')
})
it('time-picker select && input time && input date', async () => {
const value = ref('')
const wrapper = _mount(() => (
@@ -1122,4 +1151,37 @@ describe('Datetimerange', () => {
await input.trigger('focus')
expect(wrapper.findComponent(CircleClose).exists()).toBe(true)
})
it("should date input respect the default format 'YYYY-MM-DD' when format with only time format is setted", async () => {
const modelValue = [
new Date(2000, 10, 10, 10, 10),
new Date(2000, 10, 11, 10, 10),
]
const wrapper = mount(() => (
<DatePicker v-model={modelValue} format="HH:mm:ss" type="datetimerange" />
))
const input = wrapper.find('input')
await input.trigger('blur')
await input.trigger('focus')
const timeInput = document.querySelector(
'.el-date-range-picker__editors-wrap input'
)
expect((timeInput as HTMLInputElement).value).toBe('2000-11-10')
})
it("should time input respect the default format 'HH:mm:ss' when format with only date format is setted", async () => {
const modelValue = [
new Date(2000, 10, 10, 10, 10),
new Date(2000, 10, 11, 10, 10),
]
const wrapper = mount(() => (
<DatePicker v-model={modelValue} format="YYYY" type="datetimerange" />
))
const input = wrapper.find('input')
await input.trigger('blur')
await input.trigger('focus')
const timeInput = document.querySelectorAll(
'.el-date-range-picker__editors-wrap input'
)[1]
expect((timeInput as HTMLInputElement).value).toBe('10:10:00')
})
})

View File

@@ -63,11 +63,11 @@ export const timePickerDefaultProps = buildProps({
*/
valueFormat: String,
/**
* @description optional, format of the date displayed value in TimePicker's dropdown
* @description optional, format of the date displayed in input's inner panel
*/
dateFormat: String,
/**
* @description optional, format of the time displayed value in TimePicker's dropdown
* @description optional, format of the time displayed in input's inner panel
*/
timeFormat: String,
/**