Skip to content

Commit

Permalink
fix(comp:date-picker): range start and and date cover full range (#1851)
Browse files Browse the repository at this point in the history
  • Loading branch information
sallerli1 committed Feb 29, 2024
1 parent 405b050 commit 8174c4f
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 25 deletions.
12 changes: 10 additions & 2 deletions packages/components/date-picker/src/DateRangePicker.tsx
Expand Up @@ -54,7 +54,13 @@ export default defineComponent({

const { accessor, handleFocus: _handleFocus, handleBlur: _handleBlur, handleChange } = pickerStateContext

const rangeControlContext = useRangeControl(dateConfig, formatContext, inputEnableStatus, toRef(accessor, 'value'))
const rangeControlContext = useRangeControl(
dateConfig,
formatContext,
inputEnableStatus,
toRef(accessor, 'value'),
toRef(props, 'type'),
)
const handleKeyDown = useRangeKeyboardEvents(rangeControlContext, overlayOpened, setOverlayOpened, handleChange)

const { focused, handleFocus, handleBlur, bindOverlayMonitor } = useOverlayFocusMonitor(_handleFocus, _handleBlur)
Expand Down Expand Up @@ -93,7 +99,9 @@ export default defineComponent({
watch(overlayOpened, opened => {
if (opened) {
setTimeout(() => {
inputRef.value?.focus()
if (!focused.value) {
inputRef.value?.focus()
}
})
} else {
rangeControlContext.init(true)
Expand Down
34 changes: 28 additions & 6 deletions packages/components/date-picker/src/composables/useRangeControl.ts
Expand Up @@ -5,15 +5,23 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import type { DatePickerType } from '../types'
import type { DateConfig, DateConfigType, TimeConfigType } from '@idux/components/config'

import { type ComputedRef, type Ref, computed, watch } from 'vue'

import { convertArray, useState } from '@idux/cdk/utils'
import { type DateConfig } from '@idux/components/config'

import { type PickerControlContext, useControl } from './useControl'
import { type FormatContext } from './useFormat'
import { type InputEnableStatus } from './useInputEnableStatus'
import { compareDateTime, convertToDate, sortRangeValue } from '../utils'
import {
adjustRangeValue,
compareDateTime,
convertPickerTypeToConfigType,
convertToDate,
sortRangeValue,
} from '../utils'

export interface PickerRangeControlContext {
buffer: ComputedRef<(Date | undefined)[] | undefined>
Expand All @@ -34,11 +42,13 @@ export function useRangeControl(
formatContext: FormatContext,
inputEnableStatus: ComputedRef<InputEnableStatus>,
valueRef: Ref<(string | number | Date)[] | undefined>,
typeRef: Ref<DatePickerType>,
): PickerRangeControlContext {
const { formatRef } = formatContext
const [buffer, setBuffer] = useState<(Date | undefined)[] | undefined>(
const { formatRef, hourEnabled, secondEnabled, minuteEnabled } = formatContext
const convertedValue = computed(() =>
convertArray(valueRef.value).map(v => convertToDate(dateConfig, v, formatRef.value)),
)
const [buffer, setBuffer] = useState<(Date | undefined)[] | undefined>(convertedValue.value)
const [bufferUpdated, setBufferUpdated] = useState(false)
const handleBufferUpdate = (values: (string | number | Date | undefined)[] | undefined) => {
setBuffer(sortRangeValue(dateConfig, getRangeValue(dateConfig, values, formatRef.value), 'date'))
Expand Down Expand Up @@ -73,12 +83,24 @@ export function useRangeControl(
: [buffer.value?.[0], value]
}

const getAdjustedBufferValue = (value: Date | undefined, isFrom: boolean) => {
const adjustType: DateConfigType | TimeConfigType = secondEnabled.value
? 'second'
: minuteEnabled.value
? 'minute'
: hourEnabled.value
? 'hour'
: convertPickerTypeToConfigType(typeRef.value)

return adjustRangeValue(dateConfig, getValidBufferValue(value, isFrom), convertedValue.value, adjustType)
}

const fromControl = useControl(dateConfig, formatContext, inputEnableStatus, fromDateRef, value => {
setBuffer(getValidBufferValue(value, true))
setBuffer(getAdjustedBufferValue(value, true))
setBufferUpdated(true)
})
const toControl = useControl(dateConfig, formatContext, inputEnableStatus, toDateRef, value => {
setBuffer(getValidBufferValue(value, false))
setBuffer(getAdjustedBufferValue(value, false))
setBufferUpdated(true)
})

Expand Down
Expand Up @@ -12,7 +12,7 @@ import { type ComputedRef, computed, watch } from 'vue'

import { callEmit, convertArray, useState } from '@idux/cdk/utils'

import { applyDateTime, sortRangeValue } from '../utils'
import { adjustRangeValue, convertPickerTypeToConfigType, sortRangeValue } from '../utils'

export interface RangePanelStateContext {
panelValue: ComputedRef<(Date | undefined)[] | undefined>
Expand Down Expand Up @@ -53,12 +53,9 @@ export function useRangePanelState(props: DateRangePanelProps, dateConfig: DateC
callEmit(props.onSelect, [value, undefined])
} else {
const propsValue = convertArray(props.value)
const sortedValue = sortRangeValue(dateConfig, [selectingDates.value![0], value], 'date') as Date[]
handleChange(
sortRangeValue(dateConfig, [selectingDates.value![0], value], 'date').map((dateValue, index) =>
propsValue[index]
? applyDateTime(dateConfig, propsValue[index], dateValue!, ['hour', 'minute', 'second'])
: dateValue,
) as Date[],
adjustRangeValue(dateConfig, sortedValue, propsValue, convertPickerTypeToConfigType(props.type)) as Date[],
)
setIsSelecting(false)
}
Expand Down
4 changes: 2 additions & 2 deletions packages/components/date-picker/src/panel/Panel.tsx
Expand Up @@ -17,7 +17,7 @@ import { getTimePickerThemeTokens } from '@idux/components/time-picker'
import { getThemeTokens } from '../../theme'
import { useActiveValue } from '../composables/useActiveValue'
import { datePanelProps } from '../types'
import { applyDateTime } from '../utils'
import { applyDateTime, convertPickerTypeToConfigType } from '../utils'

export default defineComponent({
name: 'IxDatePanel',
Expand Down Expand Up @@ -55,7 +55,7 @@ export default defineComponent({
}

return () => {
const datePanelType = props.type === 'datetime' ? 'date' : props.type
const datePanelType = convertPickerTypeToConfigType(props.type)

const datePanelProps = {
cellTooltip: props.cellTooltip,
Expand Down
13 changes: 4 additions & 9 deletions packages/components/date-picker/src/panel/RangePanel.tsx
Expand Up @@ -19,7 +19,7 @@ import { getThemeTokens } from '../../theme'
import { useRangeActiveValue } from '../composables/useActiveValue'
import { useRangePanelState } from '../composables/useRangePanelState'
import { dateRangePanelProps } from '../types'
import { sortRangeValue } from '../utils'
import { convertPickerTypeToConfigType } from '../utils'

export default defineComponent({
name: 'IxDateRangePanel',
Expand Down Expand Up @@ -51,22 +51,17 @@ export default defineComponent({

const renderSide = (isFrom: boolean) => {
const timeValue = panelValue.value?.[isFrom ? 0 : 1]
const datePanelType = convertPickerTypeToConfigType(props.type)
const activeValue = isFrom ? fromActiveValue.value : toActiveValue.value

const handleTimePanelChange = (value: Date) => {
handleChange(
sortRangeValue(
dateConfig,
isFrom ? [value, panelValue.value?.[1]] : [panelValue.value?.[0], value],
'date',
) as Date[],
)
handleChange((isFrom ? [value, panelValue.value?.[1]] : [panelValue.value?.[0], value]) as Date[])
}

const datePanelProps = {
cellTooltip: props.cellTooltip,
disabledDate: props.disabledDate,
type: props.type === 'datetime' ? 'date' : props.type,
type: datePanelType,
value: panelValue.value,
visible: props.type === 'datetime' ? props.visible === 'datePanel' : !!props.visible,
activeDate: activeValue,
Expand Down
74 changes: 74 additions & 0 deletions packages/components/date-picker/src/utils.ts
Expand Up @@ -5,10 +5,15 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import type { DatePickerType } from './types'
import type { DateConfig, DateConfigType, TimeConfigType } from '@idux/components/config'

import { convertArray } from '@idux/cdk/utils'

export function convertPickerTypeToConfigType(type: DatePickerType): Exclude<DateConfigType, 'day'> {
return type === 'datetime' ? 'date' : type
}

export function convertToDate(
dateConfig: DateConfig,
value: string | number | Date | undefined,
Expand Down Expand Up @@ -71,3 +76,72 @@ export function sortRangeValue(
): (Date | undefined)[] {
return values.sort((v1, v2) => compareDateTime(dateConfig, v1, v2, type))
}

const typeApplySequence: (DateConfigType | TimeConfigType)[] = [
'year',
'month',
'date',
'hour',
'minute',
'second',
'millisecond',
]
function getTypeForSequenceSearch(type: DateConfigType | TimeConfigType): DateConfigType | TimeConfigType {
switch (type) {
case 'week':
return 'date'
case 'day':
return 'date'
case 'quarter':
return 'month'
default:
return type
}
}
function applyDateOfPropValue(
dateConfig: DateConfig,
value: Date,
propValue: Date,
type: DateConfigType | TimeConfigType,
): Date {
const typeForSequenceSearch = getTypeForSequenceSearch(type)
const typesToApplay = typeApplySequence.slice(typeApplySequence.indexOf(typeForSequenceSearch) + 1)

return applyDateTime(dateConfig, propValue, value, typesToApplay)
}

function adjustRangeBoundary(
dateConfig: DateConfig,
value: Date | undefined,
propValue: Date | undefined,
type: DateConfigType | TimeConfigType,
isStart: boolean,
): Date | undefined {
if (!value) {
return
}

if (propValue) {
return applyDateOfPropValue(dateConfig, value, propValue, type)
}

return isStart ? dateConfig.startOf(value, type) : dateConfig.endOf(value, type)
}

export function adjustRangeValue(
dateConfig: DateConfig,
values: (Date | undefined)[] | undefined,
propValues: undefined | (Date | undefined)[],
type: DateConfigType | TimeConfigType,
): (Date | undefined)[] | undefined {
if (!values) {
return
}

const [start, end] = values

return [
adjustRangeBoundary(dateConfig, start, propValues?.[0], type, true),
adjustRangeBoundary(dateConfig, end, propValues?.[1], type, false),
]
}

0 comments on commit 8174c4f

Please sign in to comment.