mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
fix(components): [date-picker] add missing data slot (#19839)
* feat: add missing date-picker data slot * chore: fix review & forward old test case Co-authored-by: btea <2356281422@qq.com> * Update docs/en-US/component/date-picker.md Co-authored-by: btea <2356281422@qq.com> * chore: update --------- Co-authored-by: btea <2356281422@qq.com>
This commit is contained in:
@@ -134,14 +134,15 @@ For data details, please refer:
|
||||
```ts
|
||||
interface DateCell {
|
||||
column: number
|
||||
customClass: string
|
||||
customClass: string | undefined
|
||||
disabled: boolean
|
||||
end: boolean
|
||||
inRange: boolean
|
||||
row: number
|
||||
selected: Dayjs
|
||||
isCurrent: boolean
|
||||
selected: Dayjs | undefined
|
||||
isCurrent: boolean | undefined
|
||||
isSelected: boolean
|
||||
renderText: string | undefined
|
||||
start: boolean
|
||||
text: number
|
||||
timestamp: number
|
||||
|
||||
@@ -259,13 +259,6 @@ export const useBasicDateTable = (
|
||||
}
|
||||
}
|
||||
|
||||
const isSelectedCell = (cell: DateCell) => {
|
||||
return (
|
||||
(!unref(hasCurrent) && cell?.text === 1 && cell.type === 'normal') ||
|
||||
cell.isCurrent
|
||||
)
|
||||
}
|
||||
|
||||
const handleFocus = (event: FocusEvent) => {
|
||||
if (focusWithClick || unref(hasCurrent) || props.selectionMode !== 'date')
|
||||
return
|
||||
@@ -391,7 +384,6 @@ export const useBasicDateTable = (
|
||||
focus,
|
||||
isCurrent,
|
||||
isWeekActive,
|
||||
isSelectedCell,
|
||||
|
||||
handlePickDate,
|
||||
handleMouseUp,
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
<td
|
||||
v-for="(cell, columnKey) in row"
|
||||
:key="`${rowKey}.${columnKey}`"
|
||||
:ref="(el) => !isUnmounting && isSelectedCell(cell) && (currentCellRef = el as HTMLElement)"
|
||||
:ref="(el) => !isUnmounting && cell.isSelected && (currentCellRef = el as HTMLElement)"
|
||||
:class="getCellClasses(cell)"
|
||||
:aria-current="cell.isCurrent ? 'date' : undefined"
|
||||
:aria-selected="cell.isCurrent"
|
||||
:tabindex="isSelectedCell(cell) ? 0 : -1"
|
||||
:tabindex="cell.isSelected ? 0 : -1"
|
||||
@focus="handleFocus"
|
||||
>
|
||||
<el-date-picker-cell :cell="cell" />
|
||||
@@ -68,7 +68,6 @@ const {
|
||||
focus,
|
||||
isCurrent,
|
||||
isWeekActive,
|
||||
isSelectedCell,
|
||||
|
||||
handlePickDate,
|
||||
handleMouseUp,
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
<td
|
||||
v-for="(cell, key_) in row"
|
||||
:key="key_"
|
||||
:ref="(el) => isSelectedCell(cell) && (currentCellRef = el as HTMLElement)"
|
||||
:ref="(el) => cell.isSelected && (currentCellRef = el as HTMLElement)"
|
||||
:class="getCellStyle(cell)"
|
||||
:aria-selected="`${isSelectedCell(cell)}`"
|
||||
:aria-selected="!!cell.isSelected"
|
||||
:aria-label="t(`el.datepicker.month${+cell.text + 1}`)"
|
||||
:tabindex="isSelectedCell(cell) ? 0 : -1"
|
||||
:tabindex="cell.isSelected ? 0 : -1"
|
||||
@keydown.space.prevent.stop="handleMonthTableClick"
|
||||
@keydown.enter.prevent.stop="handleMonthTableClick"
|
||||
>
|
||||
@@ -40,15 +40,25 @@ import { basicMonthTableProps } from '../props/basic-month-table'
|
||||
import { datesInMonth, getValidDateOfMonth } from '../utils'
|
||||
import ElDatePickerCell from './basic-cell-render'
|
||||
|
||||
import type { Dayjs } from 'dayjs'
|
||||
|
||||
type MonthCell = {
|
||||
column: number
|
||||
row: number
|
||||
customClass: string | undefined
|
||||
disabled: boolean
|
||||
start: boolean
|
||||
end: boolean
|
||||
text: number
|
||||
type: 'normal' | 'today'
|
||||
inRange: boolean
|
||||
row: number
|
||||
selected: Dayjs | undefined
|
||||
isCurrent: boolean | undefined
|
||||
isSelected: boolean
|
||||
start: boolean
|
||||
text: number
|
||||
renderText: string | undefined
|
||||
timestamp: number | undefined
|
||||
date: Date | undefined
|
||||
dayjs: Dayjs | undefined
|
||||
type: 'normal' | 'today'
|
||||
}
|
||||
|
||||
const props = defineProps(basicMonthTableProps)
|
||||
@@ -66,11 +76,7 @@ const months = ref(
|
||||
.monthsShort()
|
||||
.map((_) => _.toLowerCase())
|
||||
)
|
||||
const tableRows = ref<MonthCell[][]>([
|
||||
[] as MonthCell[],
|
||||
[] as MonthCell[],
|
||||
[] as MonthCell[],
|
||||
])
|
||||
const tableRows = ref<MonthCell[][]>([[], [], []])
|
||||
const lastRow = ref<number>()
|
||||
const lastColumn = ref<number>()
|
||||
const rows = computed<MonthCell[][]>(() => {
|
||||
@@ -90,6 +96,14 @@ const rows = computed<MonthCell[][]>(() => {
|
||||
end: false,
|
||||
text: -1,
|
||||
disabled: false,
|
||||
isSelected: false,
|
||||
customClass: undefined,
|
||||
date: undefined,
|
||||
dayjs: undefined,
|
||||
isCurrent: undefined,
|
||||
selected: undefined,
|
||||
renderText: undefined,
|
||||
timestamp: undefined,
|
||||
})
|
||||
|
||||
cell.type = 'normal'
|
||||
@@ -130,8 +144,14 @@ const rows = computed<MonthCell[][]>(() => {
|
||||
cell.type = 'today'
|
||||
}
|
||||
|
||||
const cellDate = calTime.toDate()
|
||||
cell.text = index
|
||||
cell.disabled = props.disabledDate?.(calTime.toDate()) || false
|
||||
cell.disabled = props.disabledDate?.(cellDate) || false
|
||||
cell.date = cellDate
|
||||
cell.customClass = props.cellClassName?.(cellDate)
|
||||
cell.dayjs = calTime
|
||||
cell.timestamp = calTime.valueOf()
|
||||
cell.isSelected = isSelectedCell(cell)
|
||||
}
|
||||
}
|
||||
return rows
|
||||
@@ -161,6 +181,9 @@ const getCellStyle = (cell: MonthCell) => {
|
||||
) >= 0
|
||||
style.today = today.getFullYear() === year && today.getMonth() === month
|
||||
|
||||
if (cell.customClass) {
|
||||
style[cell.customClass] = true
|
||||
}
|
||||
if (cell.inRange) {
|
||||
style['in-range'] = true
|
||||
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
<td
|
||||
v-for="(cell, cellKey) in row"
|
||||
:key="`${rowKey}_${cellKey}`"
|
||||
:ref="(el) => isSelectedCell(cell) && (currentCellRef = el as HTMLElement)"
|
||||
:ref="(el) => cell.isSelected && (currentCellRef = el as HTMLElement)"
|
||||
class="available"
|
||||
:class="getCellKls(cell)"
|
||||
:aria-selected="isSelectedCell(cell)"
|
||||
:aria-selected="cell.isSelected"
|
||||
:aria-label="String(cell.text)"
|
||||
:tabindex="isSelectedCell(cell) ? 0 : -1"
|
||||
:tabindex="cell.isSelected ? 0 : -1"
|
||||
@keydown.space.prevent.stop="handleYearTableClick"
|
||||
@keydown.enter.prevent.stop="handleYearTableClick"
|
||||
>
|
||||
@@ -37,15 +37,25 @@ import { basicYearTableProps } from '../props/basic-year-table'
|
||||
import { getValidDateOfYear } from '../utils'
|
||||
import ElDatePickerCell from './basic-cell-render'
|
||||
|
||||
import type { Dayjs } from 'dayjs'
|
||||
|
||||
type YearCell = {
|
||||
column: number
|
||||
row: number
|
||||
customClass: string | undefined
|
||||
disabled: boolean
|
||||
start: boolean
|
||||
end: boolean
|
||||
text: number
|
||||
type: 'normal' | 'today'
|
||||
inRange: boolean
|
||||
row: number
|
||||
selected: Dayjs | undefined
|
||||
isCurrent: boolean | undefined
|
||||
isSelected: boolean
|
||||
start: boolean
|
||||
text: number
|
||||
renderText: string | undefined
|
||||
timestamp: number | undefined
|
||||
type: 'normal' | 'today'
|
||||
date: Date | undefined
|
||||
dayjs: Dayjs | undefined
|
||||
}
|
||||
|
||||
const datesInYear = (year: number, lang: string) => {
|
||||
@@ -91,6 +101,14 @@ const rows = computed(() => {
|
||||
end: false,
|
||||
text: -1,
|
||||
disabled: false,
|
||||
isSelected: false,
|
||||
customClass: undefined,
|
||||
date: undefined,
|
||||
dayjs: undefined,
|
||||
isCurrent: undefined,
|
||||
selected: undefined,
|
||||
renderText: undefined,
|
||||
timestamp: undefined,
|
||||
}
|
||||
}
|
||||
cell.type = 'normal'
|
||||
@@ -131,8 +149,12 @@ const rows = computed(() => {
|
||||
}
|
||||
cell.text = index
|
||||
const cellDate = calTime.toDate()
|
||||
cell.disabled =
|
||||
(props.disabledDate && props.disabledDate(cellDate)) || false
|
||||
cell.disabled = props.disabledDate?.(cellDate) || false
|
||||
cell.date = cellDate
|
||||
cell.customClass = props.cellClassName?.(cellDate)
|
||||
cell.dayjs = calTime
|
||||
cell.timestamp = calTime.valueOf()
|
||||
cell.isSelected = isSelectedCell(cell)
|
||||
row[j] = cell
|
||||
}
|
||||
}
|
||||
@@ -158,6 +180,9 @@ const getCellKls = (cell: YearCell) => {
|
||||
kls.current =
|
||||
castArray(props.parsedValue).findIndex((d) => d!.year() === year) >= 0
|
||||
|
||||
if (cell.customClass) {
|
||||
kls[cell.customClass] = true
|
||||
}
|
||||
if (cell.inRange) {
|
||||
kls['in-range'] = true
|
||||
|
||||
|
||||
@@ -166,6 +166,7 @@
|
||||
:disabled-date="disabledDate"
|
||||
:disabled="disabled"
|
||||
:parsed-value="parsedValue"
|
||||
:cell-class-name="cellClassName"
|
||||
@pick="handleYearPick"
|
||||
/>
|
||||
<month-table
|
||||
@@ -176,6 +177,7 @@
|
||||
:parsed-value="parsedValue"
|
||||
:disabled-date="disabledDate"
|
||||
:disabled="disabled"
|
||||
:cell-class-name="cellClassName"
|
||||
@pick="handleMonthPick"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
:range-state="rangeState"
|
||||
:disabled-date="disabledDate"
|
||||
:disabled="disabled"
|
||||
:cell-class-name="cellClassName"
|
||||
@changerange="handleChangeRange"
|
||||
@pick="handleRangePick"
|
||||
@select="onSelect"
|
||||
@@ -103,6 +104,7 @@
|
||||
:range-state="rangeState"
|
||||
:disabled-date="disabledDate"
|
||||
:disabled="disabled"
|
||||
:cell-class-name="cellClassName"
|
||||
@changerange="handleChangeRange"
|
||||
@pick="handleRangePick"
|
||||
@select="onSelect"
|
||||
@@ -151,7 +153,7 @@ const isDefaultFormat = inject(
|
||||
ROOT_PICKER_IS_DEFAULT_FORMAT_INJECTION_KEY,
|
||||
undefined
|
||||
) as any
|
||||
const { shortcuts, disabledDate } = pickerBase.props
|
||||
const { shortcuts, disabledDate, cellClassName } = pickerBase.props
|
||||
const format = toRef(pickerBase.props, 'format')
|
||||
const defaultValue = toRef(pickerBase.props, 'defaultValue')
|
||||
const leftDate = ref(dayjs().locale(lang.value))
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
:range-state="rangeState"
|
||||
:disabled-date="disabledDate"
|
||||
:disabled="disabled"
|
||||
:cell-class-name="cellClassName"
|
||||
@changerange="handleChangeRange"
|
||||
@pick="handleRangePick"
|
||||
@select="onSelect"
|
||||
@@ -86,6 +87,7 @@
|
||||
:range-state="rangeState"
|
||||
:disabled-date="disabledDate"
|
||||
:disabled="disabled"
|
||||
:cell-class-name="cellClassName"
|
||||
@changerange="handleChangeRange"
|
||||
@pick="handleRangePick"
|
||||
@select="onSelect"
|
||||
@@ -137,7 +139,7 @@ const isDefaultFormat = inject(
|
||||
undefined
|
||||
) as any
|
||||
const pickerBase = inject(PICKER_BASE_INJECTION_KEY) as any
|
||||
const { shortcuts, disabledDate } = pickerBase.props
|
||||
const { shortcuts, disabledDate, cellClassName } = pickerBase.props
|
||||
const format = toRef(pickerBase.props, 'format')
|
||||
const defaultValue = toRef(pickerBase.props, 'defaultValue')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { buildProps, definePropType } from '@element-plus/utils'
|
||||
import { buildProps } from '@element-plus/utils'
|
||||
import { datePickerSharedProps, selectionModeWithDefault } from './shared'
|
||||
|
||||
import type { ExtractPropTypes, __ExtractPublicPropTypes } from 'vue'
|
||||
@@ -6,9 +6,6 @@ import type { Dayjs } from 'dayjs'
|
||||
|
||||
export const basicDateTableProps = buildProps({
|
||||
...datePickerSharedProps,
|
||||
cellClassName: {
|
||||
type: definePropType<(date: Date) => string>(Function),
|
||||
},
|
||||
showWeekNumber: Boolean,
|
||||
selectionMode: selectionModeWithDefault('date'),
|
||||
} as const)
|
||||
|
||||
@@ -23,8 +23,12 @@ export type RangeState = {
|
||||
}
|
||||
|
||||
export type DisabledDateType = (date: Date) => boolean
|
||||
export type CellClassNameType = (date: Date) => string
|
||||
|
||||
export const datePickerSharedProps = buildProps({
|
||||
cellClassName: {
|
||||
type: definePropType<CellClassNameType>(Function),
|
||||
},
|
||||
disabledDate: {
|
||||
type: definePropType<DisabledDateType>(Function),
|
||||
},
|
||||
|
||||
@@ -588,6 +588,64 @@ describe('DatePicker', () => {
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
it('should have same common propreties for default slot', async () => {
|
||||
const testCellData = (cell) => {
|
||||
const cellProperties = [
|
||||
'column',
|
||||
'type',
|
||||
'text',
|
||||
'start',
|
||||
'timestamp',
|
||||
'dayjs',
|
||||
'date',
|
||||
'isSelected',
|
||||
'inRange',
|
||||
'row',
|
||||
'customClass',
|
||||
'end',
|
||||
] //TODO: we should later increase the list in order to fit DateCell perfectly
|
||||
expect(Object.keys(cell)).toEqual(expect.arrayContaining(cellProperties))
|
||||
const values = Object.entries(cell)
|
||||
.filter(([key]) => cellProperties.includes(key))
|
||||
.map(([, val]) => val)
|
||||
for (const value of values) {
|
||||
expect(value).toBeDefined()
|
||||
}
|
||||
}
|
||||
const wrapper = _mount(
|
||||
`
|
||||
<el-date-picker :cellClassName="() => 'hello'">
|
||||
<template #default="cell">
|
||||
<div class="custom-cell" data-testid="" @click="testCellData(cell)">
|
||||
click me
|
||||
</div>
|
||||
</template>
|
||||
</el-date-picker>
|
||||
`,
|
||||
() => ({ testCellData })
|
||||
)
|
||||
const types = [
|
||||
'year',
|
||||
'years',
|
||||
'month',
|
||||
'months',
|
||||
'date',
|
||||
'dates',
|
||||
'week',
|
||||
'datetime',
|
||||
'datetimerange',
|
||||
'daterange',
|
||||
'monthrange',
|
||||
'yearrange',
|
||||
]
|
||||
for (const type of types) {
|
||||
await wrapper.setProps({ type })
|
||||
{
|
||||
;(document.querySelector('.custom-cell') as HTMLElement).click()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('custom content', async () => {
|
||||
const wrapper = _mount(
|
||||
`<el-date-picker
|
||||
|
||||
Reference in New Issue
Block a user