import React, { useState, useEffect, useRef, useCallback } from "react"; import classNames from "classnames"; import moment, { Moment } from "moment"; import CalendarPart from "../calendar/CalendarPart"; import { ControlledProps, useDefaultValue } from "../form/controlled"; import { CalendarTable } from "../calendar/CalendarTable"; import { Input } from "../input/Input"; import { DropdownBox } from "../dropdown"; import { CommonDatePickerProps } from "./DatePickerProps"; import { useTranslation } from "../i18n"; import { CalendarTableType, DateChangeContext } from "../calendar/DateProps"; import { Popover } from "../popover/Popover"; import { DatePickerTrigger, isAfter, isBefore, isValidDate, isValidMonth, } from "./util"; import { useDefault } from "../_util/use-default"; import { useConfig } from "../_util/config-context"; import { Icon } from "../icon"; import { noop } from "../_util/noop"; import { forwardRefWithStatics } from "../_util/forward-ref-with-statics"; import { mergeEventProps } from "../_util/merge-event-props"; import { KeyMap } from "../_util/key-map"; export interface MonthPickerProps extends CommonDatePickerProps, ControlledProps { /** * 设置不可选月份,返回: * * - `true` 可选 * - `false` 不可选 * * @since 2.5.0 */ disabledMonth?: (date: Moment) => boolean; } export const MonthPicker = forwardRefWithStatics( function MonthPicker( props: MonthPickerProps, ref: React.Ref ) { const t = useTranslation(moment); const { classPrefix } = useConfig(); const { header, className, style, value, onChange, onInputValueChange = noop, disabled, format = "YYYY-MM", placeholder = t.selectDate, defaultOpen = false, open, onOpenChange = noop, placement = "bottom-start", placementOffset = 5, closeOnScroll = true, escapeWithReference, popupContainer, overlayClassName, overlayStyle, clearable, } = useDefaultValue(props); const [hover, setHover] = useState(false); // 当前面板类型 const [type, setType] = useState("month"); // 当前面板展示时间 const [curViewMoment, setCurViewMoment] = useState( moment.isMoment(value) ? value : getDefaultViewMoment() ); // 当前选中日期 const [curValue, setCurValue] = useState(value); // 选择器是否展开 const [active, setActive] = useDefault(open, defaultOpen, onOpenChange); useEffect(() => { setCurValue(value); // eslint-disable-next-line react-hooks/exhaustive-deps }, [active]); // 输入框显示值 const inputRef = useRef(null); const getInputValue = useCallback( value => { return moment.isMoment(value) ? value.locale(t.locale).format(format) : ""; }, [t.locale, format] ); const [inputValue, setInputValue] = useState( getInputValue(curValue) ); const syncInputValue = useCallback( (value: Moment) => { const inputValue = getInputValue(value); setInputValue(inputValue); onInputValueChange(inputValue, { valid: true }); }, // eslint-disable-next-line react-hooks/exhaustive-deps [getInputValue] ); useEffect(() => { setCurValue(value); syncInputValue(value); }, [format, value, getInputValue, syncInputValue]); useEffect(() => { setCurViewMoment(curValue); }, [curValue]); function getDefaultViewMoment(): Moment { const { range } = props; const m = moment(); // range 判断 if (Array.isArray(range)) { let [start, end] = range; if (!moment.isMoment(start)) { start = moment(0); } if (!moment.isMoment(end)) { end = moment(2 ** 52); } if (isBefore(end, m, "year")) { return end; } if (isAfter(start, m, "year")) { return start; } } return m; } function handleChange(value: Moment, context: DateChangeContext) { setCurValue(value); syncInputValue(value); onChange(value, context); handleClose(); } function handleOpen() { if (disabled) { return; } setActive(true); setType("month"); } function handleClose() { syncInputValue(value); setActive(false); } function handleInputChange(content: string) { setInputValue(content); const value = moment(content, format, true); if (!value.isValid()) { onInputValueChange(content, { valid: false }); return; } const valid = isValidMonth(value, props); if (valid) { setCurValue(value); } onInputValueChange(content, { valid: true }); } function handleKeyDown(event: React.KeyboardEvent) { if (!active) { handleOpen(); return; } switch (event.key) { case KeyMap.Enter: onChange(curValue, { event }); handleClose(); break; case KeyMap.Esc: handleClose(); break; } } return ( {!!header && {header}} } >
setHover(true)} onMouseLeave={() => setHover(false)} > { if (active) { event.stopPropagation(); } }} /> {clearable && !disabled && ( { event.stopPropagation(); onChange(null, { event }); }} /> )}
); }, { defaultLabelAlign: "middle", } ); MonthPicker.displayName = "MonthPicker";