diff --git a/packages/zent/assets/date-picker.scss b/packages/zent/assets/date-picker.scss index 3f995d95c1..3052eab116 100644 --- a/packages/zent/assets/date-picker.scss +++ b/packages/zent/assets/date-picker.scss @@ -153,6 +153,10 @@ width: 280px; cursor: pointer; + &_lunar { + width: 330px; + } + &-header { @include font-large; display: flex; @@ -223,6 +227,16 @@ box-sizing: border-box; } + .zent-datepicker-lunar-cell { + display: block; + width: 32px; + height: 38px; + + &_text { + font-size: $font-size-small; + } + } + &_current { .zent-datepicker-cell-inner { @include border-with-radius; diff --git a/packages/zent/package.json b/packages/zent/package.json index fdcd61a2c5..7e8f6f2cf2 100644 --- a/packages/zent/package.json +++ b/packages/zent/package.json @@ -45,6 +45,7 @@ "big.js": "^6.1.1", "classnames": "^2.2.6", "date-fns": "^2.7.0", + "lunar-typescript": "^1.6.10", "observable-hooks": "^4.1.0", "react-is": "^17.0.1", "react-transition-group": "^4.4.1", diff --git a/packages/zent/src/date-picker/DatePicker.tsx b/packages/zent/src/date-picker/DatePicker.tsx index ebe179a642..b0623a3ee5 100644 --- a/packages/zent/src/date-picker/DatePicker.tsx +++ b/packages/zent/src/date-picker/DatePicker.tsx @@ -27,6 +27,8 @@ export interface IDatePickerProps showTime?: IShowTime; disabledTime?: IDisabledTime; hideFooter?: boolean; + showLunarDate?: boolean; + lunarValueFormatter?: (date: Date) => string; } const defaultDatePickerProps = { format: DATE_FORMAT, diff --git a/packages/zent/src/date-picker/README_en-US.md b/packages/zent/src/date-picker/README_en-US.md index 0f5770c33a..b1d70f931b 100644 --- a/packages/zent/src/date-picker/README_en-US.md +++ b/packages/zent/src/date-picker/README_en-US.md @@ -51,12 +51,15 @@ interface IDisableDateMap { | hideFooter | Whether to show footer | `boolean` | `false` | No | | showTime | To provide an additional time selection | `boolean` \| `object` | `false` | No | | disabledTime | To specify the time that cannot be selected | `(date?: Date) => IDisabledTimeOption` | - | No | +| showLunarDate | Whether to display lunar date | `boolean` | `false` | No | +| lunarValueFormatter | Format lunar date backfill value | `(date: Date) => string` | - | No | **Additional** - When return value of `showTime` is an object, to provide an additional time selection, there are some properties within this object: `format`、`hourStep`、`minuteStep`、`secondStep`, but redefines the type of `defaultTime` to be `string | (date: Date) => string` - `disabledTime` only works with `showTime`, see the details in `TimePicker` - `format` should be `'YYYY-MM-DD HH:mm:ss'` when `showTime` is `true` +- `lunarValueFormatter` only works with `showLunarDate` #### WeekPicker API diff --git a/packages/zent/src/date-picker/README_zh-CN.md b/packages/zent/src/date-picker/README_zh-CN.md index 0491f5f8aa..b3209f7e4c 100644 --- a/packages/zent/src/date-picker/README_zh-CN.md +++ b/packages/zent/src/date-picker/README_zh-CN.md @@ -56,12 +56,16 @@ interface IDisableDateMap { | hideFooter | 隐藏面板底部 | `boolean` | `false` | 否 | | showTime | 是否支持时间选择功能 | `boolean` \| `object` | `false` | 否 | | disabledTime | 时间禁用判断 | `(date?: Date) => IDisabledTimeOption` | - | 否 | +| showLunarDate | 是否显示农历日期 | `boolean` | `false` | 否 | +| lunarValueFormatter | 格式化农历日期回填值 | `(date: Date) => string` | - | 否 | **注意:** - `showTime` 为对象时,表示支持时间选择,具体属性可参考 `TimePicker`,包括 `format`、`hourStep`、`minuteStep`、`secondStep`,其中 `defaultTime` 类型定义为 `string | (date: Date) => string` - `disabledTime` 在 `showTime` 开启时生效,可参考 `TimePicker` 的 `IDisabledTimeOption` - `showTime` 时 `format` 值应为`'YYYY-MM-DD HH:mm:ss'`,使用时注意 `format` 参数 +- `showTime` 时 `format` 值应为`'YYYY-MM-DD HH:mm:ss'`,使用时注意 `format` 参数 +- `lunarValueFormatter` 在 `showLunarDate` 开启时生效 ### WeekPicker 其他 API diff --git a/packages/zent/src/date-picker/components/PanelCell.tsx b/packages/zent/src/date-picker/components/PanelCell.tsx index e4fc313915..1a9d3521d0 100644 --- a/packages/zent/src/date-picker/components/PanelCell.tsx +++ b/packages/zent/src/date-picker/components/PanelCell.tsx @@ -57,7 +57,7 @@ const PanelCell: React.FC = ({ const rows = useMemo(() => { const uls: React.ReactNode[] = []; let rowCells: React.ReactNode[] = []; - cells.map(({ value, text, ...classNameProps }, index) => { + cells.map(({ value, text, lunarText, ...classNameProps }, index) => { const { isSelected, isDisabled } = classNameProps; const cellNode = (
  • = ({ className={getCellClassName(classNameProps)} onClick={() => onCellClick({ isDisabled, value })} > -
    onCellMouseOver({ isDisabled, value })} - onMouseLeave={() => onCellMouseOver({ isDisabled, value: null })} - > - {text} -
    + {lunarText ? ( +
    onCellMouseOver({ isDisabled, value })} + onMouseLeave={() => onCellMouseOver({ isDisabled, value: null })} + > +
    {text}
    +
    {lunarText}
    +
    + ) : ( +
    onCellMouseOver({ isDisabled, value })} + onMouseLeave={() => onCellMouseOver({ isDisabled, value: null })} + > + {text} +
    + )}
  • ); // 单元格支持Tooltip diff --git a/packages/zent/src/date-picker/components/SinglePickerBase.tsx b/packages/zent/src/date-picker/components/SinglePickerBase.tsx index cd91e375c9..c6060ea701 100644 --- a/packages/zent/src/date-picker/components/SinglePickerBase.tsx +++ b/packages/zent/src/date-picker/components/SinglePickerBase.tsx @@ -49,6 +49,9 @@ export function SinglePicker({ PanelComponent, ...restPanelProps } = restPropsRef.current; + const { showLunarDate, lunarValueFormatter } = + restPanelProps as ISinglePanelProps; + const { getSelectedValue, getCallbackValue, getInputText } = useContext(PickerContext); // props onChangeRef @@ -114,10 +117,19 @@ export function SinglePicker({ ); // trigger-input text - const text = useMemo( - () => getInputText?.(selected), - [selected, getInputText] - ); + const text = useMemo(() => { + if (!selected) return ''; + + if ( + showLunarDate && + lunarValueFormatter && + typeof lunarValueFormatter === 'function' + ) { + return lunarValueFormatter(selected); + } + + return getInputText?.(selected); + }, [selected, showLunarDate, getInputText, lunarValueFormatter]); const trigger = useMemo(() => { const triggerProps = pick(restPropsRef.current, triggerCommonProps); @@ -137,7 +149,11 @@ export function SinglePicker({ const content = useMemo(() => { return ( -
    +
    ); }, [ + showLunarDate, + PanelComponent, + restPanelProps, selected, hoverDate, defaultPanelDate, - restPanelProps, - disabledPanelDate, onSelected, - PanelComponent, + disabledPanelDate, ]); return ( diff --git a/packages/zent/src/date-picker/demos/lunar.md b/packages/zent/src/date-picker/demos/lunar.md new file mode 100644 index 0000000000..a5801ced68 --- /dev/null +++ b/packages/zent/src/date-picker/demos/lunar.md @@ -0,0 +1,47 @@ +--- +order: 10 +zh-CN: + title: 农历日期选择 +en-US: + title: Lunar date picker +--- + +```jsx +import { DatePicker } from 'zent'; +import { useState } from 'react'; + +import { Lunar } from 'lunar-typescript'; + +class LunarDatePickerDemo extends Component { + state = {}; + + lunarValueFormatter = date => { + const d = Lunar.fromDate(date); + return d.toString(); + }; + + handleDateChange = val => { + this.setState({ + date: val, + }); + }; + + render() { + const { date } = this.state; + return ( + + ); + } +} + +ReactDOM.render(, mountNode); +``` + + diff --git a/packages/zent/src/date-picker/panels/date-panel/DateBody.tsx b/packages/zent/src/date-picker/panels/date-panel/DateBody.tsx index ad2751b23b..ff25dd024f 100644 --- a/packages/zent/src/date-picker/panels/date-panel/DateBody.tsx +++ b/packages/zent/src/date-picker/panels/date-panel/DateBody.tsx @@ -41,6 +41,7 @@ const DatePickerBody: FC = props => { showTimeOption, onSelected, disabledPanelDate, + showLunarDate, } = props; const startDateOfMonth = useMemo( @@ -62,6 +63,7 @@ const DatePickerBody: FC = props => { dateConfig: dateConfig.date, inView: isSameMonth, disableRangeOverView, + showLunarDate, }), [ disableRangeOverView, @@ -72,6 +74,7 @@ const DatePickerBody: FC = props => { col, startDateOfMonth, disabledPanelDate, + showLunarDate, ] ); diff --git a/packages/zent/src/date-picker/panels/date-panel/index.tsx b/packages/zent/src/date-picker/panels/date-panel/index.tsx index 6fc27aa311..38535e9705 100644 --- a/packages/zent/src/date-picker/panels/date-panel/index.tsx +++ b/packages/zent/src/date-picker/panels/date-panel/index.tsx @@ -13,6 +13,8 @@ import usePanelDate from '../../hooks/usePanelDate'; import { ISinglePanelProps, IDisabledTime, IShowTime } from '../../types'; import { useEventCallbackRef } from '../../../utils/hooks/useEventCallbackRef'; +import { Lunar } from 'lunar-typescript'; + export interface IDatePickerPanelProps extends ISinglePanelProps { disableRangeOverView?: boolean; popText?: string; @@ -44,6 +46,23 @@ const DatePickerPanel: React.FC = props => { const showTimeOption = useShowTimeOption(showTime); const onPanelDateChangeRef = useEventCallbackRef(onPanelDateChange); + const { showLunarDate } = resetBodyProps; + + const monthLabel = useMemo(() => { + const solarMonth = panelDate.getMonth(); + + const solarMonthLabel = i18n.panel.monthNames[solarMonth]; + if (!showLunarDate) { + return solarMonthLabel; + } + + const d = Lunar.fromDate(new Date(panelDate.getFullYear(), solarMonth)); + + const lunar = d.getMonthInChinese(); + + return `${solarMonthLabel}(${lunar}月)`; + }, [showLunarDate, i18n.panel.monthNames, panelDate]); + const titleNode = useMemo( () => ( <> @@ -52,13 +71,10 @@ const DatePickerPanel: React.FC = props => { unit={i18n.panel.year} onClick={() => setShowYear(true)} /> - setShowMonth(true)} - /> + <Title text={monthLabel} onClick={() => setShowMonth(true)} /> </> ), - [panelDate, i18n] + [panelDate, i18n.panel.year, monthLabel] ); const modifyPanelDate = useCallback( diff --git a/packages/zent/src/date-picker/types.ts b/packages/zent/src/date-picker/types.ts index 392816d538..d243cc99ca 100644 --- a/packages/zent/src/date-picker/types.ts +++ b/packages/zent/src/date-picker/types.ts @@ -72,6 +72,7 @@ interface ICommonProps<DateValue = SingleDate> { export interface IDateCellBase { value: Date; text: string | number; + lunarText?: string | number; isSelected?: boolean; isCurrent?: boolean; isDisabled?: boolean; @@ -146,6 +147,8 @@ export interface ISinglePanelProps { onSelected: (val: Date, status?: boolean) => void; disabledPanelDate: (val: Date) => boolean; onChangePanel?: (type: IPickerType) => void; + showLunarDate?: boolean; + lunarValueFormatter?: (date: Date) => string; } export type ISingleDateBodyProps = Omit<ISinglePanelProps, 'onChangePanel'>; diff --git a/packages/zent/src/date-picker/utils/getPanelCellsData.ts b/packages/zent/src/date-picker/utils/getPanelCellsData.ts index 313cc684bc..19063b92cf 100644 --- a/packages/zent/src/date-picker/utils/getPanelCellsData.ts +++ b/packages/zent/src/date-picker/utils/getPanelCellsData.ts @@ -1,5 +1,6 @@ import { eachDayOfInterval, isAfter, isBefore, isSameDay } from 'date-fns'; import { IDateCellBase, IGenerateDateConfig, DateTuple } from '../types'; +import { Lunar } from 'lunar-typescript'; interface ICellDateParams { selected: Date | null; @@ -14,6 +15,8 @@ interface ICellDateParams { offset?: number; inView?: (val1: Date, val2: Date) => boolean; disableRangeOverView?: boolean; + showLunarDate?: boolean; + lunarValueFormatter?: (date: Date) => string; } /** @@ -33,6 +36,7 @@ export default function getPanelCellsData({ offset = 0, inView, disableRangeOverView, + showLunarDate, }: ICellDateParams) { const { isSame, startDate, endDate, offsetDate } = dateConfig; @@ -43,6 +47,22 @@ export default function getPanelCellsData({ const currentDate = offsetDate(defaultPanelDate, index - offset); const text = texts ? texts[index] : currentDate.getDate(); + let lunarText = ''; + + if (showLunarDate) { + const date = currentDate as any; + + const d = Lunar.fromDate(date); + const lunarDay = d.getDayInChinese(); + const solarTerm = d.getJieQi(); + + if (1 === d.getDay()) { + lunarText = d.getMonthInChinese() + '月'; + } else { + lunarText = solarTerm || lunarDay; + } + } + const isCurrent = isSame(new Date(), currentDate); const isInView = inView ? inView(currentDate, defaultPanelDate) : true; @@ -92,6 +112,7 @@ export default function getPanelCellsData({ cells[index] = { value: currentDate, text, + lunarText, isCurrent, isSelected, isInView, diff --git a/yarn.lock b/yarn.lock index d1fa27ef32..51d7cdd734 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7398,6 +7398,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lunar-typescript@^1.6.10: + version "1.6.10" + resolved "https://registry.npmmirror.com/lunar-typescript/-/lunar-typescript-1.6.10.tgz#607b5d6821efb48c0ff751a79859b1dfeb39c7a6" + integrity sha512-NpimyKWfxaYbUPJIdHcDX5iaXSMbQVob2yk4Baox9KMwCNLrLsjNk/sS92fAlqTkziKkvM/39rPxk4qXX7gWaA== + lunr@^2.3.9: version "2.3.9" resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1"