mirror of
https://github.com/element-plus/element-plus.git
synced 2025-03-07 15:47:57 +08:00
fix(components): [date-picker] disabledDate is invalid when selecting year or month picker (#15848)
* fix(components): [date-picker] props.disabledDate is invalid when selecting year or month picker * test(components): [date-picker] props disabledDate * fix(components): [date-picker] props.disabledDate is invalid * fix: test * fix: error * fix: Disable time validation for date selectors of years and months * fix: test * fix: [date-picker] props.disabledDate is invalid * fix: [date-picker] props.disabledDate is invalid --------- Co-authored-by: qiang <qw13131wang@gmail.com>
This commit is contained in:
parent
e815102d70
commit
9aa70ecd4e
@ -365,6 +365,66 @@ describe('DatePicker', () => {
|
||||
expect(document.querySelector('.disabled')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('select year picker when using disabledDate prop', async () => {
|
||||
const wrapper = _mount(
|
||||
`<el-date-picker
|
||||
v-model="value"
|
||||
:disabledDate="disabledDate"
|
||||
/>`,
|
||||
() => ({
|
||||
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(
|
||||
`<el-date-picker
|
||||
v-model="value"
|
||||
:disabledDate="disabledDate"
|
||||
/>`,
|
||||
() => ({
|
||||
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(
|
||||
`<el-date-picker
|
||||
|
@ -35,9 +35,9 @@
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
import { useLocale, useNamespace } from '@element-plus/hooks'
|
||||
import { rangeArr } from '@element-plus/components/time-picker'
|
||||
import { castArray, hasClass } from '@element-plus/utils'
|
||||
import { basicMonthTableProps } from '../props/basic-month-table'
|
||||
import { datesInMonth, getValidDateOfMonth } from '../utils'
|
||||
import ElDatePickerCell from './basic-cell-render'
|
||||
|
||||
type MonthCell = {
|
||||
@ -51,12 +51,6 @@ type MonthCell = {
|
||||
inRange: boolean
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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<DisabledDateType>(Function),
|
||||
},
|
||||
date: {
|
||||
type: definePropType<Dayjs>(Object),
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user