diff --git a/packages/components/date-picker/__tests__/date-picker.test.ts b/packages/components/date-picker/__tests__/date-picker.test.ts
index d96795aba3..5f75a605a8 100644
--- a/packages/components/date-picker/__tests__/date-picker.test.ts
+++ b/packages/components/date-picker/__tests__/date-picker.test.ts
@@ -365,6 +365,66 @@ describe('DatePicker', () => {
expect(document.querySelector('.disabled')).not.toBeNull()
})
+ it('select year picker when using disabledDate prop', async () => {
+ const wrapper = _mount(
+ ``,
+ () => ({
+ value: '2024-01-01',
+ disabledDate(time) {
+ const dayTime = new Date(2023, 1, 4).getTime()
+ return time.getTime() < dayTime
+ },
+ })
+ )
+ const input = wrapper.find('input')
+ input.trigger('blur')
+ input.trigger('focus')
+ await nextTick()
+ const yearLabel: HTMLElement = document.querySelectorAll(
+ '.el-date-picker__header-label'
+ )[0]
+ yearLabel.click()
+ await nextTick()
+ const yearCells = document.querySelectorAll('.el-date-table-cell__text')
+ const year2023 = [...yearCells].find((item) => item.innerHTML === '2023')
+ year2023.click()
+ await nextTick()
+ expect(input.element.value).toBe('2023-02-04')
+ })
+
+ it('select month picker when using disabledDate prop', async () => {
+ const wrapper = _mount(
+ ``,
+ () => ({
+ value: '2023-05-01',
+ disabledDate(time) {
+ const dayTime = new Date(2023, 1, 4).getTime()
+ return time.getTime() < dayTime
+ },
+ })
+ )
+ const input = wrapper.find('input')
+ input.trigger('blur')
+ input.trigger('focus')
+ await nextTick()
+ const monthLabel: HTMLElement = document.querySelectorAll(
+ '.el-date-picker__header-label'
+ )[1]
+ monthLabel.click()
+ await nextTick()
+ const monthCells = document.querySelectorAll('.el-date-table-cell__text')
+ const februaryCell = monthCells[1]
+ februaryCell.click()
+ await nextTick()
+ expect(input.element.value).toBe('2023-02-04')
+ })
+
it('should work when using disabledDate prop and daterange type', async () => {
const wrapper = _mount(
` {
- const firstDay = dayjs().locale(lang).startOf('month').month(month).year(year)
- const numOfDays = firstDay.daysInMonth()
- return rangeArr(numOfDays).map((n) => firstDay.add(n, 'day').toDate())
-}
-
const props = defineProps(basicMonthTableProps)
const emit = defineEmits(['changerange', 'pick', 'select'])
@@ -230,11 +224,15 @@ const handleMonthTableClick = (event: MouseEvent | KeyboardEvent) => {
emit('pick', castArray(props.parsedValue), false)
return
}
- const newMonth = props.date.startOf('month').month(month)
-
+ const newMonth = getValidDateOfMonth(
+ props.date.year(),
+ month,
+ lang.value,
+ props.disabledDate
+ )
const newValue = hasClass(target, 'current')
? castArray(props.parsedValue).filter(
- (d) => Number(d) !== Number(newMonth)
+ (d) => d?.month() !== newMonth.month()
)
: castArray(props.parsedValue).concat([dayjs(newMonth)])
emit('pick', newValue)
diff --git a/packages/components/date-picker/src/date-picker-com/basic-year-table.vue b/packages/components/date-picker/src/date-picker-com/basic-year-table.vue
index d5a65decd5..5d5b74bbe1 100644
--- a/packages/components/date-picker/src/date-picker-com/basic-year-table.vue
+++ b/packages/components/date-picker/src/date-picker-com/basic-year-table.vue
@@ -34,6 +34,7 @@ import { useLocale, useNamespace } from '@element-plus/hooks'
import { rangeArr } from '@element-plus/components/time-picker'
import { castArray, hasClass } from '@element-plus/utils'
import { basicYearTableProps } from '../props/basic-year-table'
+import { getValidDateOfYear } from '../utils'
import ElDatePickerCell from './basic-cell-render'
type YearCell = {
@@ -201,9 +202,14 @@ const handleYearTableClick = (event: MouseEvent | KeyboardEvent) => {
emit('pick', castArray(props.parsedValue), false)
return
}
+ const vaildYear = getValidDateOfYear(
+ newDate.startOf('year'),
+ lang.value,
+ props.disabledDate
+ )
const newValue = hasClass(target, 'current')
? castArray(props.parsedValue).filter((d) => d?.year() !== selectedYear)
- : castArray(props.parsedValue).concat([newDate])
+ : castArray(props.parsedValue).concat([vaildYear])
emit('pick', newValue)
} else {
emit('pick', selectedYear)
diff --git a/packages/components/date-picker/src/date-picker-com/panel-date-pick.vue b/packages/components/date-picker/src/date-picker-com/panel-date-pick.vue
index f7110fd4d4..1c92090d77 100644
--- a/packages/components/date-picker/src/date-picker-com/panel-date-pick.vue
+++ b/packages/components/date-picker/src/date-picker-com/panel-date-pick.vue
@@ -224,6 +224,7 @@ import {
} from '@element-plus/icons-vue'
import { TOOLTIP_INJECTION_KEY } from '@element-plus/components/tooltip'
import { panelDatePickProps } from '../props/panel-date-pick'
+import { getValidDateOfMonth, getValidDateOfYear } from '../utils'
import DateTable from './basic-date-table.vue'
import MonthTable from './basic-month-table.vue'
import YearTable from './basic-year-table.vue'
@@ -429,12 +430,22 @@ const handleMonthPick = async (
keepOpen?: boolean
) => {
if (selectionMode.value === 'month') {
- innerDate.value = innerDate.value.startOf('month').month(month as number)
+ innerDate.value = getValidDateOfMonth(
+ innerDate.value.year(),
+ month as number,
+ lang.value,
+ disabledDate
+ )
emit(innerDate.value, false)
} else if (selectionMode.value === 'months') {
emit(month as MonthsPickerEmits, keepOpen ?? true)
} else {
- innerDate.value = innerDate.value.startOf('month').month(month as number)
+ innerDate.value = getValidDateOfMonth(
+ innerDate.value.year(),
+ month as number,
+ lang.value,
+ disabledDate
+ )
currentView.value = 'date'
if (['month', 'year', 'date', 'week'].includes(selectionMode.value)) {
emit(innerDate.value, true)
@@ -450,12 +461,14 @@ const handleYearPick = async (
keepOpen?: boolean
) => {
if (selectionMode.value === 'year') {
- innerDate.value = innerDate.value.startOf('year').year(year as number)
+ const data = innerDate.value.startOf('year').year(year as number)
+ innerDate.value = getValidDateOfYear(data, lang.value, disabledDate)
emit(innerDate.value, false)
} else if (selectionMode.value === 'years') {
emit(year as YearsPickerEmits, keepOpen ?? true)
} else {
- innerDate.value = innerDate.value.year(year as number)
+ const data = innerDate.value.year(year as number)
+ innerDate.value = getValidDateOfYear(data, lang.value, disabledDate)
currentView.value = 'month'
if (['month', 'year', 'date', 'week'].includes(selectionMode.value)) {
emit(innerDate.value, true)
diff --git a/packages/components/date-picker/src/props/shared.ts b/packages/components/date-picker/src/props/shared.ts
index bc15a71236..86aac5d51c 100644
--- a/packages/components/date-picker/src/props/shared.ts
+++ b/packages/components/date-picker/src/props/shared.ts
@@ -21,9 +21,11 @@ export type RangeState = {
selecting: boolean
}
+export type DisabledDateType = (date: Date) => boolean
+
export const datePickerSharedProps = buildProps({
disabledDate: {
- type: definePropType<(date: Date) => boolean>(Function),
+ type: definePropType(Function),
},
date: {
type: definePropType(Object),
diff --git a/packages/components/date-picker/src/utils.ts b/packages/components/date-picker/src/utils.ts
index edd05a7eb5..337792c346 100644
--- a/packages/components/date-picker/src/utils.ts
+++ b/packages/components/date-picker/src/utils.ts
@@ -1,8 +1,10 @@
import dayjs from 'dayjs'
import { isArray } from '@element-plus/utils'
+import { rangeArr } from '@element-plus/components/time-picker'
import type { Dayjs } from 'dayjs'
import type { DateCell } from './date-picker.type'
+import type { DisabledDateType } from './props/shared'
type DayRange = [Dayjs | undefined, Dayjs | undefined]
@@ -132,3 +134,46 @@ export const buildPickerTable = (
setRowMetadata?.(row)
}
}
+
+export const datesInMonth = (year: number, month: number, lang: string) => {
+ const firstDay = dayjs().locale(lang).startOf('month').month(month).year(year)
+ const numOfDays = firstDay.daysInMonth()
+ return rangeArr(numOfDays).map((n) => firstDay.add(n, 'day').toDate())
+}
+
+export const getValidDateOfMonth = (
+ year: number,
+ month: number,
+ lang: string,
+ disabledDate?: DisabledDateType
+) => {
+ const _value = dayjs().year(year).month(month).startOf('month')
+ const _date = datesInMonth(year, month, lang).find((date) => {
+ return !disabledDate?.(date)
+ })
+ if (_date) {
+ return dayjs(_date).locale(lang)
+ }
+ return _value.locale(lang)
+}
+
+export const getValidDateOfYear = (
+ value: Dayjs,
+ lang: string,
+ disabledDate?: DisabledDateType
+) => {
+ const year = value.year()
+ if (!disabledDate?.(value.toDate())) {
+ return value.locale(lang)
+ }
+ const month = value.month()
+ if (!datesInMonth(year, month, lang).every(disabledDate)) {
+ return getValidDateOfMonth(year, month, lang, disabledDate)
+ }
+ for (let i = 0; i < 12; i++) {
+ if (!datesInMonth(year, i, lang).every(disabledDate)) {
+ return getValidDateOfMonth(year, i, lang, disabledDate)
+ }
+ }
+ return value
+}