Skip to content

Commit

Permalink
feat(date-picker): Add needConfirm and onConfirm api (#2979)
Browse files Browse the repository at this point in the history
  • Loading branch information
zyprepare committed Aug 28, 2024
1 parent 8d4571c commit cac65e6
Show file tree
Hide file tree
Showing 11 changed files with 184 additions and 74 deletions.
5 changes: 5 additions & 0 deletions .changeset/silver-ads-jog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hi-ui/date-picker": minor
---

feat: Add needConfirm and onConfirm api
5 changes: 5 additions & 0 deletions .changeset/slow-bottles-talk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hi-ui/hiui": patch
---

feat(date-picker): Add needConfirm and onConfirm api
29 changes: 24 additions & 5 deletions packages/ui/date-picker/src/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ export const DatePicker = forwardRef<HTMLDivElement | null, DatePickerProps>(
footerRender,
strideSelectMode = 'auto',
prefix,
needConfirm: needConfirmProp = false,
onConfirm,
...otherProps
},
ref
Expand All @@ -92,6 +94,14 @@ export const DatePicker = forwardRef<HTMLDivElement | null, DatePickerProps>(
const [inputFocus, setInputFocus] = useState(false)
const [type, setType] = useState<DatePickerTypeEnum>(propType)

const needConfirm = useMemo(() => {
// 如果是日期时间范围选择,则默认返回 true
if (type === 'daterange' && showTime) {
return true
}
return needConfirmProp
}, [needConfirmProp, showTime, type])

useEffect(() => {
moment.locale(locale === 'en-US' ? 'en' : 'zh-CN')
// V4: 不使用 weekOffset 判断国际化语言
Expand Down Expand Up @@ -301,12 +311,10 @@ export const DatePicker = forwardRef<HTMLDivElement | null, DatePickerProps>(
setInputFocus(false)
}, [])

const isInDateRangeTimeMode = useMemo(() => type === 'daterange' && showTime, [type, showTime])

const onPopperClose = useCallback(() => {
resetStatus()

if (!isInDateRangeTimeMode) {
if (!needConfirm) {
const outDateValue = outDate[0]
const isValid = moment(outDateValue).isValid()
// @ts-ignore
Expand All @@ -322,7 +330,7 @@ export const DatePicker = forwardRef<HTMLDivElement | null, DatePickerProps>(
}

onClose?.()
}, [resetStatus, outDate, isInDateRangeTimeMode, onClose, max, min, callback, changeOutDate])
}, [callback, changeOutDate, max, min, needConfirm, onClose, outDate, resetStatus])

const onClear = () => {
resetStatus()
Expand All @@ -349,8 +357,11 @@ export const DatePicker = forwardRef<HTMLDivElement | null, DatePickerProps>(
type === 'timeperiod' && `${prefixCls}__popper--timeperiod`,
shortcuts && `${prefixCls}__popper--shortcuts`
)

const [attachEl, setAttachEl] = useState<HTMLElement | null>(null)

const isInDateRangeTimeMode = useMemo(() => type === 'daterange' && showTime, [type, showTime])

const popContent = useMemo(() => {
// 日期时间范围选择器特殊处理
if (isInDateRangeTimeMode) {
Expand All @@ -367,7 +378,13 @@ export const DatePicker = forwardRef<HTMLDivElement | null, DatePickerProps>(
{type.includes('range') || type === 'timeperiod' ? (
<RangePanel />
) : (
<Panel onPick={onPick} outDate={outDate} disabledDate={disabledDate} />
<Panel
onPick={onPick}
outDate={outDate}
disabledDate={disabledDate}
needConfirm={needConfirm}
onConfirm={onConfirm}
/>
)}
</div>
)
Expand All @@ -378,6 +395,8 @@ export const DatePicker = forwardRef<HTMLDivElement | null, DatePickerProps>(
onPick,
outDate,
disabledDate,
needConfirm,
onConfirm,
dateRangeTimePanelNow,
])

Expand Down
18 changes: 3 additions & 15 deletions packages/ui/date-picker/src/components/date-range-time-panel.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'
import { useLocaleContext } from '@hi-ui/core'
import HiButton from '@hi-ui/button'
import DPContext, { DPContextData } from '../context'
import Panel from './panel'
import { CalenderSelectedRange } from '../hooks/useCalenderData'
import moment from 'moment'
import { CalendarViewEnum } from '../types'
import { Footer } from './footer'

interface DateRangeTimePanelProps {
nowIndex: number
Expand All @@ -14,8 +13,7 @@ interface DateRangeTimePanelProps {

// 选择日期范围,并且希望选择时间
export const DateRangeTimePanel = (props: DateRangeTimePanelProps) => {
const i18n = useLocaleContext()
const { outDate, onPick, disabledDate, prefixCls, footerRender } = useContext(DPContext)
const { outDate, onPick, disabledDate } = useContext(DPContext)
const { nowIndex, onChangeNowIndex } = props

const [range, setRange] = useState<CalenderSelectedRange>({
Expand Down Expand Up @@ -94,16 +92,6 @@ export const DateRangeTimePanel = (props: DateRangeTimePanelProps) => {
return nowIndex === 0 ? !range.start : !range.end
}, [nowIndex, range])

const footer = useMemo(() => {
const sureActionContent = (
<HiButton type="primary" disabled={isConfirmButtonDisabled} onClick={onConfirmButtonClick}>
{i18n.get('datePicker.ok')}
</HiButton>
)

return typeof footerRender === 'function' ? footerRender(sureActionContent) : sureActionContent
}, [footerRender, i18n, isConfirmButtonDisabled, onConfirmButtonClick])

return (
<React.Fragment>
<Panel
Expand All @@ -112,7 +100,7 @@ export const DateRangeTimePanel = (props: DateRangeTimePanelProps) => {
outDate={panelData}
range={range}
/>
<div className={`${prefixCls}__date-range-time-bottom`}>{footer}</div>
<Footer disabled={isConfirmButtonDisabled} onConfirmButtonClick={onConfirmButtonClick} />
</React.Fragment>
)
}
26 changes: 26 additions & 0 deletions packages/ui/date-picker/src/components/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, { FC, useContext, useMemo } from 'react'
import { useLocaleContext } from '@hi-ui/core'
import HiButton from '@hi-ui/button'
import DPContext from '../context'

interface FooterProps {
disabled?: boolean
onConfirmButtonClick: () => void
}

export const Footer: FC<FooterProps> = ({ disabled, onConfirmButtonClick }) => {
const i18n = useLocaleContext()
const { prefixCls, footerRender, size } = useContext(DPContext)

const footer = useMemo(() => {
const sureActionContent = (
<HiButton type="primary" disabled={disabled} onClick={onConfirmButtonClick} size={size}>
{i18n.get('datePicker.ok')}
</HiButton>
)

return typeof footerRender === 'function' ? footerRender(sureActionContent) : sureActionContent
}, [disabled, footerRender, i18n, onConfirmButtonClick, size])

return <div className={`${prefixCls}__footer`}>{footer}</div>
}
119 changes: 70 additions & 49 deletions packages/ui/date-picker/src/components/panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ import { timePickerValueAdaptor } from '../utils/timePickerValueAdaptor'
import { useTimePickerFormat } from '../hooks/useTimePickerFormat'
import { getBelongWeekRange } from '../utils/week'
import { CalenderSelectedRange } from '../hooks/useCalenderData'
import { Footer } from './footer'

interface PanelProps {
onPick: DPContextData['onPick']
outDate: (moment.Moment | null)[]
disabledDate: DPContextData['disabledDate']
range?: CalenderSelectedRange
needConfirm?: boolean
onConfirm?: DPContextData['onConfirm']
}
const Panel = (props: PanelProps) => {
const { onPick, outDate, range, disabledDate } = props
const { onPick: onPickProp, outDate, range, disabledDate, needConfirm, onConfirm } = props
const {
// outDate,
type,
Expand Down Expand Up @@ -60,6 +63,13 @@ const Panel = (props: PanelProps) => {
setCalRenderDates([rDate])
}, [outDate])

const onPick = useCallback(
(dates: (moment.Moment | null)[], isShowPanel?: boolean) => {
onPickProp(dates, needConfirm ? true : isShowPanel)
},
[needConfirm, onPickProp]
)

const onCalenderPick = useCallback(
(date: moment.Moment) => {
onSelect(date as any, true)
Expand Down Expand Up @@ -116,7 +126,7 @@ const Panel = (props: PanelProps) => {
const panelCls = cx(
`${prefixCls}__panel`,
`theme__${theme}`,
showTime && `${prefixCls}__panel--time ${prefixCls}__panel--noshadow`
(showTime || needConfirm) && `${prefixCls}__panel--time ${prefixCls}__panel--noshadow`
)

const timePickerFormat = useTimePickerFormat(realFormat)
Expand Down Expand Up @@ -149,56 +159,67 @@ const Panel = (props: PanelProps) => {
}

return (
<div className={panelCls}>
<div className={`${prefixCls}__panel--left`}>
{calRenderDates[0] && (
<React.Fragment>
<Header
renderDate={calRenderDates[0]}
// 疑问:尚未找到这个 props
// renderDates={calRenderDates}
changeView={() => setView('year')}
onArrowEvent={onArrowEvent}
i18n={i18n}
view={view}
panelPosition={0}
// 疑问:尚未找到这个 props
// type={type}
locale={locale}
prefixCls={prefixCls}
/>
<Calendar
renderDate={calRenderDates[0]}
originDate={outDate[0]}
onPick={onCalenderPick}
view={view}
disabledDate={disabledDate}
range={range}
// panelPosition="left"
/>
</React.Fragment>
<>
<div className={panelCls}>
<div className={`${prefixCls}__panel--left`}>
{calRenderDates[0] && (
<React.Fragment>
<Header
renderDate={calRenderDates[0]}
// 疑问:尚未找到这个 props
// renderDates={calRenderDates}
changeView={() => setView('year')}
onArrowEvent={onArrowEvent}
i18n={i18n}
view={view}
panelPosition={0}
// 疑问:尚未找到这个 props
// type={type}
locale={locale}
prefixCls={prefixCls}
/>
<Calendar
renderDate={calRenderDates[0]}
originDate={outDate[0]}
onPick={onCalenderPick}
view={view}
disabledDate={disabledDate}
range={range}
// panelPosition="left"
/>
</React.Fragment>
)}
</div>
{showTime && (
<div className={`${prefixCls}__panel__time-container`}>
<div className={`${prefixCls}__panel__time-header`}>{timePickerData[0]}</div>
<div className={`${prefixCls}__panel__time-content`}>
<TimePickerPopContent
onChange={onTimeChange}
value={timePickerData}
hourStep={hourStep}
minuteStep={minuteStep}
secondStep={secondStep}
type="single"
format={timePickerFormat}
disabledHours={disabledHours}
disabledMinutes={disabledMinutes}
disabledSeconds={disabledSeconds}
/>
</div>
</div>
)}
</div>
{showTime && (
<div className={`${prefixCls}__panel__time-container`}>
<div className={`${prefixCls}__panel__time-header`}>{timePickerData[0]}</div>
<div className={`${prefixCls}__panel__time-content`}>
<TimePickerPopContent
onChange={onTimeChange}
value={timePickerData}
hourStep={hourStep}
minuteStep={minuteStep}
secondStep={secondStep}
type="single"
format={timePickerFormat}
disabledHours={disabledHours}
disabledMinutes={disabledMinutes}
disabledSeconds={disabledSeconds}
/>
</div>
</div>
{needConfirm && (
<Footer
disabled={!outDate[0]}
onConfirmButtonClick={() => {
onPickProp(calRenderDates, false)
onConfirm?.(calRenderDates[0].toDate())
}}
/>
)}
</div>
</>
)
}

Expand Down
5 changes: 3 additions & 2 deletions packages/ui/date-picker/src/components/range-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -384,10 +384,11 @@ const RangePanel = () => {
))}
</div>
</div>
{/* 目前不会执行到该逻辑 */}
{type === 'daterange' && showTime && (
<div
className={`${prefixCls}__footer ${
!isDisableFooter ? `${prefixCls}__footer--disable` : ''
className={`${prefixCls}-old ${
!isDisableFooter ? `${prefixCls}__footer-old--disable` : ''
}`}
onClick={() => {
isDisableFooter && setShowRangeMask(true)
Expand Down
6 changes: 3 additions & 3 deletions packages/ui/date-picker/src/styles/date-picker.scss
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ $calendar-large-background-border-radius: $calendar-large-indicator-border-radiu
}
}

&__footer {
&__footer-old {
height: 48px;
border-top: 1px solid use-color('gray', 100);
box-sizing: border-box;
Expand All @@ -719,7 +719,7 @@ $calendar-large-background-border-radius: $calendar-large-indicator-border-radiu
font-size: 14px;
width: 100%;

&:not(.#{$prefix}__footer--disable):hover {
&:not(.#{$prefix}__footer-old--disable):hover {
color: use-color-mode('primary');
}

Expand Down Expand Up @@ -866,7 +866,7 @@ $calendar-large-background-border-radius: $calendar-large-indicator-border-radiu
}
}

&__date-range-time-bottom {
&__footer {
display: flex;
justify-content: space-between;
padding: 6px 8px;
Expand Down
9 changes: 9 additions & 0 deletions packages/ui/date-picker/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,4 +287,13 @@ export interface DatePickerProps extends Omit<HiBaseHTMLProps<'div'>, 'placehold
* 选择框前置内容
*/
prefix?: React.ReactNode
/**
* 是否需要确认按钮,为 <code>false</code> 时失去焦点即代表选择。日期时间范围选择默认为 <code>true</code>
* @default false
*/
needConfirm?: boolean
/**
* 点击确认按钮的回调
*/
onConfirm?: (date: Date) => void
}
1 change: 1 addition & 0 deletions packages/ui/date-picker/stories/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export * from './lunar.stories'
export * from './size.stories'
export * from './footer-render.stories'
export * from './addon.stories'
export * from './need-confirm.stories'

export default {
title: 'Data Input/DatePicker',
Expand Down
Loading

0 comments on commit cac65e6

Please sign in to comment.