Skip to content

Commit

Permalink
feat(date-picker): #2621
Browse files Browse the repository at this point in the history
  • Loading branch information
zyprepare committed Oct 20, 2023
1 parent 9174d39 commit 48a16f4
Show file tree
Hide file tree
Showing 13 changed files with 183 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .changeset/eighty-terms-agree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hi-ui/hiui": patch
---

DatePicker feat: 增加 strideSelectMode API & format 支持函数
5 changes: 5 additions & 0 deletions .changeset/funny-peaches-carry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hi-ui/date-picker": minor
---

feat: 增加 strideSelectMode API & format 支持函数
8 changes: 5 additions & 3 deletions packages/ui/date-picker/src/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export const DatePicker = forwardRef<HTMLDivElement | null, DatePickerProps>(
invalid = false,
onClose,
cellRender,
strideSelectMode = 'auto',
...otherProps
},
ref
Expand Down Expand Up @@ -169,20 +170,20 @@ export const DatePicker = forwardRef<HTMLDivElement | null, DatePickerProps>(
valueAdapter,
uncontrolledValue,
])

const [outDate, changeOutDate] = useDate({
value,
type,
defaultValue,
cacheDate,
format,
format: typeof format === 'function' ? undefined : format,
weekOffset: safeWeekOffset,
locale,
strideSelectMode,
})
const realFormat = useFormat({
type,
showTime,
format,
format: typeof format === 'function' ? undefined : format,
locale,
})

Expand Down Expand Up @@ -416,6 +417,7 @@ export const DatePicker = forwardRef<HTMLDivElement | null, DatePickerProps>(
isInDateRangeTimeMode,
size,
cellRender,
strideSelectMode,
}}
>
<div className={cx(prefixCls, className)} {...otherProps}>
Expand Down
11 changes: 4 additions & 7 deletions packages/ui/date-picker/src/components/calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const Calendar = ({
_class.push(`${prefixCls}__cell--out`)
break
default:
_class.push(`${prefixCls}__cell--${td.type}`)
!td.weekNum && _class.push(`${prefixCls}__cell--${td.type}`)
break
}

Expand Down Expand Up @@ -120,24 +120,21 @@ const Calendar = ({
if (!['SPAN', 'DIV'].includes(td.nodeName) || td.getAttribute('type') === 'disabled') {
return false
}

const clickVal = parseInt(value)
const _date = moment(renderDate) as any
const cellType = td.getAttribute('type')
const cellWeekType = td.getAttribute('weektype')

// 如果点击的是周数,则直接拿到该周的周一日期返回
if (cellType === 'week') {
onPick(moment().isoWeek(clickVal))
return false
}

if (type !== 'weekrange' || isBelongFullOurOfRange) {
if (cellType === 'prev' || cellWeekType === 'prev') {
_date.subtract(1, 'months')
}

if (cellType === 'next' || cellWeekType === 'next') {
_date.add(1, 'months')
}

_date[view](clickVal)
} else {
// 点击的上个月的部分,鼠标还在本月的panel上,则视作,鼠标正在本月第一天
Expand Down
20 changes: 17 additions & 3 deletions packages/ui/date-picker/src/components/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ const Input = ({

const cacheValues = useRef<string | null>(null)
const [value, setValue] = useState<string | null>('')

useEffect(() => {
let vals = date && moment(date).format(realFormat)

if (type.includes('week') && date) {
// const _date = moment(date).year(y)
// vals = moment(_date).format(realFormat)
Expand All @@ -51,26 +53,38 @@ const Input = ({
week: getBelongWeek(date, weekOffset),
})
} else {
const y = moment(date).weekYear()
const _date = moment(date).year(y)
vals = moment(_date).format(realFormat)
if (typeof format === 'function') {
vals = format(date)
} else {
const y = moment(date).weekYear()
const _date = moment(date).year(y)

vals = moment(_date).format(realFormat)
}
}
}

setValue(vals)

cacheValues.current = vals
}, [date, weekOffset, i18n, type, format, realFormat, locale])

const inputChangeEvent = (e: React.ChangeEvent<HTMLInputElement>) => {
const val = e.target.value

setValue(val)

if (val && val.trim().length === realFormat.length) {
const nVal = moment(val)

if (nVal.isValid()) {
onChange(nVal, dir)
} else {
setValue(cacheValues.current)
}
}
}

return (
<div className={`${prefixCls}__picker__input-container`}>
<input
Expand Down
2 changes: 2 additions & 0 deletions packages/ui/date-picker/src/components/panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,12 @@ const Panel = (props: PanelProps) => {
}
setView(_view)
const _innerDates = genNewDates(calRenderDates, date)

if (view === 'date') {
onPick(_innerDates, showTime)
return
}

setCalRenderDates(_innerDates)
},
[calRenderDates, onPick, onSelect, showTime, type, view, weekOffset]
Expand Down
37 changes: 36 additions & 1 deletion packages/ui/date-picker/src/components/range-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const RangePanel = () => {
showPanel,
prefixCls,
disabledDate,
strideSelectMode,
} = useContext(DPContext)
const calendarClickIsEnd = useRef(false)
const [showRangeMask, setShowRangeMask] = useState(false)
Expand All @@ -51,6 +52,7 @@ const RangePanel = () => {

useEffect(() => {
const _outDate = cloneDeep(outDate)

setRange({
start: _outDate[0],
end: _outDate[1],
Expand Down Expand Up @@ -95,11 +97,44 @@ const RangePanel = () => {
newRange.end = newRange.start
newRange.start = date
}

// 此处是明显的语法错误,故而注释修改
// onSelect(date, calendarClickIsEnd)
onSelect(date as any, !calendarClickIsEnd.current)

if (type === 'weekrange') {
onPick([newRange.start!.startOf('week'), newRange.end!.endOf('week')], showTime)
// 固定模式下,即使跨月选择了日期,仍然显示当前月的日期选择面板
if (strideSelectMode === 'fixed') {
const { start, end } = newRange
// 开始周周一日期
const startOfWeek = start.clone()!.startOf('week')
// 结束周周日日期
const endOfWeek = end!.clone()!.endOf('week')
// 当月最后一天
const endOfMonth = end!.clone().endOf('month')
// 重新计算出的开始日期,逻辑:(开始周日期不能是上个月的日期)
// 如果当前日期是当月第一天,则返回当前日期,否则
// 如果当前日期小于当前周周一,则返回当月第一天,否则返回当前周周一
const rangeStart =
start.date() === 1
? start
: startOfWeek.date() > start.date()
? start.clone().startOf('month')
: startOfWeek
// 重新计算出的结束日期,逻辑:(结束周日期不能是下个月的日期)
// 如果当前日期是当月最后一天,则返回当前日期,否则
// 如果当前日期大于当前周周日,则返回当月最后一天,否则返回当前周周日
const rangeEnd =
end?.date() === endOfMonth.date()
? end
: end!.date() > endOfWeek.date()
? endOfMonth
: endOfWeek

onPick([rangeStart, rangeEnd], showTime)
} else {
onPick([newRange.start!.startOf('week'), newRange.end!.endOf('week')], showTime)
}
} else {
onPick([newRange.start, newRange.end], showTime)
}
Expand Down
17 changes: 15 additions & 2 deletions packages/ui/date-picker/src/components/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const Root = ({
min,
max,
size,
strideSelectMode,
} = useContext(DPContext)
const [inputData, setInputData] = useState(outDate)

Expand All @@ -52,9 +53,21 @@ const Root = ({
placeholder,
i18n,
})

useEffect(() => {
setInputData(value ? parseValue(value, type, weekOffset, format) : outDate)
}, [value, format, type, outDate, weekOffset])
setInputData(
value
? parseValue(
value,
type,
weekOffset,
typeof format === 'string' ? format : undefined,
strideSelectMode
)
: outDate
)
}, [value, format, type, outDate, weekOffset, strideSelectMode])

const onPickerClickEvent = (index: number) => {
if (disabled) return
onTrigger(index)
Expand Down
1 change: 1 addition & 0 deletions packages/ui/date-picker/src/hooks/useCalenderData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ const getDateRows = ({
}
}

// 新增功能:周选择显示周数
// 如果是周类型,则计算出每一行的周数并放入每行数组第一个
if (type === 'week' || type === 'weekrange') {
const year = _date.year()
Expand Down
28 changes: 24 additions & 4 deletions packages/ui/date-picker/src/hooks/useData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,27 @@ interface IUseDateConfig {
cacheDate: React.MutableRefObject<(moment.Moment | null)[]>
type: DatePickerTypeEnum
weekOffset: number
strideSelectMode?: 'auto' | 'fixed'
}

export const useDate = (config: IUseDateConfig) => {
const { value, defaultValue, cacheDate, type, format, locale, weekOffset } = config
const {
value,
defaultValue,
cacheDate,
type,
format,
locale,
weekOffset,
strideSelectMode,
} = config

const [outDate, setOutDate] = useState<(moment.Moment | null)[]>(() => {
const d = parseValue(value || defaultValue, type, weekOffset, format as any) as any
const _value = value || defaultValue
const d = parseValue(_value, type, weekOffset, format as any, strideSelectMode) as any

cacheDate.current = d

return d
})

Expand All @@ -25,14 +40,19 @@ export const useDate = (config: IUseDateConfig) => {
dates[0] && moment(dates[0]).isValid() ? dates[0] : null,
dates[1] && moment(dates[1]).isValid() ? dates[1] : null,
]

setOutDate(_datas as any)
}

useEffect(() => {
if (value === undefined) return
const d = parseValue(value, type, weekOffset, format as any) as any

const d = parseValue(value, type, weekOffset, format as any, strideSelectMode) as any

setOutDate(d)

cacheDate.current = d
}, [value, type, weekOffset, format, locale, setOutDate, cacheDate])
}, [value, type, weekOffset, format, locale, setOutDate, cacheDate, strideSelectMode])

return [outDate, changeOutDate] as const
}
10 changes: 9 additions & 1 deletion packages/ui/date-picker/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { HiBaseHTMLProps } from '@hi-ui/core'
import { PopperOverlayProps } from '@hi-ui/popper'
import { TimePickerPanelType } from '@hi-ui/time-picker'
import { CalendarColInfo } from './hooks/useCalenderData'
import { Moment } from 'moment'

export type CalendarViewEnum = 'date' | 'year' | 'month'

Expand Down Expand Up @@ -157,7 +158,7 @@ export interface DatePickerProps extends Omit<HiBaseHTMLProps<'div'>, 'placehold
/**
* 展示的日期格式,配置参考 [moment.js](http://momentjs.cn/docs/#/displaying/format/)
*/
format?: string
format?: string | ((date: Moment) => string)
/**
* 快捷面板
*/
Expand Down Expand Up @@ -261,4 +262,11 @@ export interface DatePickerProps extends Omit<HiBaseHTMLProps<'div'>, 'placehold
* 自定义单元格内容
*/
cellRender?: (colInfo: CalendarColInfo) => React.ReactNode
/**
* 跨月选择模式
* 'auto' 自动切换模式,跨月选择时自动切换到跨月的日期选择面板;
* 'fixed' 固定模式,不自动切换(仅周范围选择下生效)
* @default 'auto'
*/
strideSelectMode?: 'auto' | 'fixed'
}
14 changes: 12 additions & 2 deletions packages/ui/date-picker/src/utils/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -294,28 +294,38 @@ export const parseValue = (
value: DatePickerValueV3,
type: DatePickerTypeEnum,
weekOffset: number,
format?: string
format?: string,
strideSelectMode?: 'auto' | 'fixed'
) => {
if (!value) return [null]

// 暂时无法理解为何此处自行获取了 type
// const _format = getLocaleTypeFormatMap(locale)[type]
// const _value = moment(value as any, _format)
const _value = moment(value as any, format)
const _value = moment(value as any, typeof format === 'string' ? format : undefined)
const isValid = moment(_value).isValid()

if (value && typeof value === 'object' && (type.includes('range') || type === 'timeperiod')) {
const rangeValue = value as DateRange

if (type === 'weekrange') {
if (strideSelectMode === 'fixed') {
return [moment(rangeValue.start), moment(rangeValue.end)]
}

return [
rangeValue.start ? getBelongWeekBoundary(moment(rangeValue.start), weekOffset) : null,
rangeValue.end ? getBelongWeekBoundary(moment(rangeValue.end), weekOffset, false) : null,
]
}

return [
rangeValue.start && moment(rangeValue.start).isValid()
? moment(rangeValue.start, format)
: null,
rangeValue.end && moment(rangeValue.end).isValid() ? moment(rangeValue.end, format) : null,
]
}

return [isValid ? _value : null]
}
Loading

0 comments on commit 48a16f4

Please sign in to comment.