614 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Vue
		
	
	
			
		
		
	
	
			614 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Vue
		
	
	
| /**
 | |
|  * Logic:
 | |
|  *  When `mode` === `picker`,
 | |
|  *  click will trigger `onSelect` (if value changed trigger `onChange` also).
 | |
|  *  Panel change will not trigger `onSelect` but trigger `onPanelChange`
 | |
|  */
 | |
| import type { SharedTimeProps } from './panels/TimePanel';
 | |
| import TimePanel from './panels/TimePanel';
 | |
| import DatetimePanel from './panels/DatetimePanel';
 | |
| import DatePanel from './panels/DatePanel';
 | |
| import WeekPanel from './panels/WeekPanel';
 | |
| import MonthPanel from './panels/MonthPanel';
 | |
| import QuarterPanel from './panels/QuarterPanel';
 | |
| import YearPanel from './panels/YearPanel';
 | |
| import DecadePanel from './panels/DecadePanel';
 | |
| import type { GenerateConfig } from './generate';
 | |
| import type {
 | |
|   Locale,
 | |
|   PanelMode,
 | |
|   PanelRefProps,
 | |
|   PickerMode,
 | |
|   DisabledTime,
 | |
|   OnPanelChange,
 | |
|   Components,
 | |
| } from './interface';
 | |
| import { isEqual } from './utils/dateUtil';
 | |
| import { useInjectPanel, useProvidePanel } from './PanelContext';
 | |
| import type { DateRender } from './panels/DatePanel/DateBody';
 | |
| import { PickerModeMap } from './utils/uiUtil';
 | |
| import type { MonthCellRender } from './panels/MonthPanel/MonthBody';
 | |
| import { useInjectRange } from './RangeContext';
 | |
| import getExtraFooter from './utils/getExtraFooter';
 | |
| import getRanges from './utils/getRanges';
 | |
| import { getLowerBoundTime, setDateTime, setTime } from './utils/timeUtil';
 | |
| import type { VueNode } from '../_util/type';
 | |
| import { computed, createVNode, defineComponent, ref, toRef, watch, watchEffect } from 'vue';
 | |
| import useMergedState from '../_util/hooks/useMergedState';
 | |
| import { warning } from '../vc-util/warning';
 | |
| import KeyCode from '../_util/KeyCode';
 | |
| import classNames from '../_util/classNames';
 | |
| 
 | |
| export type PickerPanelSharedProps<DateType> = {
 | |
|   prefixCls?: string;
 | |
|   // className?: string;
 | |
|   // style?: React.CSSProperties;
 | |
|   /** @deprecated Will be removed in next big version. Please use `mode` instead */
 | |
|   mode?: PanelMode;
 | |
|   tabindex?: number;
 | |
| 
 | |
|   // Locale
 | |
|   locale: Locale;
 | |
|   generateConfig: GenerateConfig<DateType>;
 | |
| 
 | |
|   // Value
 | |
|   value?: DateType | null;
 | |
|   defaultValue?: DateType;
 | |
|   /** [Legacy] Set default display picker view date */
 | |
|   pickerValue?: DateType;
 | |
|   /** [Legacy] Set default display picker view date */
 | |
|   defaultPickerValue?: DateType;
 | |
| 
 | |
|   // Date
 | |
|   disabledDate?: (date: DateType) => boolean;
 | |
| 
 | |
|   // Render
 | |
|   dateRender?: DateRender<DateType>;
 | |
|   monthCellRender?: MonthCellRender<DateType>;
 | |
|   renderExtraFooter?: (mode: PanelMode) => VueNode;
 | |
| 
 | |
|   // Event
 | |
|   onSelect?: (value: DateType) => void;
 | |
|   onChange?: (value: DateType) => void;
 | |
|   onPanelChange?: OnPanelChange<DateType>;
 | |
|   onMousedown?: (e: MouseEvent) => void;
 | |
|   onOk?: (date: DateType) => void;
 | |
| 
 | |
|   direction?: 'ltr' | 'rtl';
 | |
| 
 | |
|   /** @private This is internal usage. Do not use in your production env */
 | |
|   hideHeader?: boolean;
 | |
|   /** @private This is internal usage. Do not use in your production env */
 | |
|   onPickerValueChange?: (date: DateType) => void;
 | |
| 
 | |
|   /** @private Internal usage. Do not use in your production env */
 | |
|   components?: Components;
 | |
| };
 | |
| 
 | |
| export type PickerPanelBaseProps<DateType> = {
 | |
|   picker: Exclude<PickerMode, 'date' | 'time'>;
 | |
| } & PickerPanelSharedProps<DateType>;
 | |
| 
 | |
| export type PickerPanelDateProps<DateType> = {
 | |
|   picker?: 'date';
 | |
|   showToday?: boolean;
 | |
|   showNow?: boolean;
 | |
| 
 | |
|   // Time
 | |
|   showTime?: boolean | SharedTimeProps<DateType>;
 | |
|   disabledTime?: DisabledTime<DateType>;
 | |
| } & PickerPanelSharedProps<DateType>;
 | |
| 
 | |
| export type PickerPanelTimeProps<DateType> = {
 | |
|   picker: 'time';
 | |
| } & PickerPanelSharedProps<DateType> &
 | |
|   SharedTimeProps<DateType>;
 | |
| 
 | |
| export type PickerPanelProps<DateType> =
 | |
|   | PickerPanelBaseProps<DateType>
 | |
|   | PickerPanelDateProps<DateType>
 | |
|   | PickerPanelTimeProps<DateType>;
 | |
| 
 | |
| // TMP type to fit for ts 3.9.2
 | |
| type OmitType<DateType> = Omit<PickerPanelBaseProps<DateType>, 'picker'> &
 | |
|   Omit<PickerPanelDateProps<DateType>, 'picker'> &
 | |
|   Omit<PickerPanelTimeProps<DateType>, 'picker'>;
 | |
| type MergedPickerPanelProps<DateType> = {
 | |
|   picker?: PickerMode;
 | |
| } & OmitType<DateType>;
 | |
| 
 | |
| function PickerPanel<DateType>() {
 | |
|   return defineComponent<MergedPickerPanelProps<DateType>>({
 | |
|     name: 'PickerPanel',
 | |
|     inheritAttrs: false,
 | |
|     props: {
 | |
|       prefixCls: String,
 | |
|       locale: Object,
 | |
|       generateConfig: Object,
 | |
|       value: Object,
 | |
|       defaultValue: Object,
 | |
|       pickerValue: Object,
 | |
|       defaultPickerValue: Object,
 | |
|       disabledDate: Function,
 | |
|       mode: String,
 | |
|       picker: { type: String, default: 'date' },
 | |
|       tabindex: { type: [Number, String], default: 0 },
 | |
|       showNow: { type: Boolean, default: undefined },
 | |
|       showTime: [Boolean, Object],
 | |
|       showToday: Boolean,
 | |
|       renderExtraFooter: Function,
 | |
|       dateRender: Function,
 | |
|       hideHeader: { type: Boolean, default: undefined },
 | |
|       onSelect: Function,
 | |
|       onChange: Function,
 | |
|       onPanelChange: Function,
 | |
|       onMousedown: Function,
 | |
|       onPickerValueChange: Function,
 | |
|       onOk: Function,
 | |
|       components: Object,
 | |
|       direction: String,
 | |
|       hourStep: { type: Number, default: 1 },
 | |
|       minuteStep: { type: Number, default: 1 },
 | |
|       secondStep: { type: Number, default: 1 },
 | |
|     } as any,
 | |
|     setup(props, { attrs }) {
 | |
|       const needConfirmButton = computed(
 | |
|         () => (props.picker === 'date' && !!props.showTime) || props.picker === 'time',
 | |
|       );
 | |
| 
 | |
|       const isHourStepValid = computed(() => 24 % props.hourStep === 0);
 | |
|       const isMinuteStepValid = computed(() => 60 % props.minuteStep === 0);
 | |
|       const isSecondStepValid = computed(() => 60 % props.secondStep === 0);
 | |
|       if (process.env.NODE_ENV !== 'production') {
 | |
|         watchEffect(() => {
 | |
|           const { generateConfig, value, hourStep = 1, minuteStep = 1, secondStep = 1 } = props;
 | |
|           warning(!value || generateConfig.isValidate(value), 'Invalidate date pass to `value`.');
 | |
|           warning(
 | |
|             !value || generateConfig.isValidate(value),
 | |
|             'Invalidate date pass to `defaultValue`.',
 | |
|           );
 | |
|           warning(
 | |
|             isHourStepValid.value,
 | |
|             `\`hourStep\` ${hourStep} is invalid. It should be a factor of 24.`,
 | |
|           );
 | |
|           warning(
 | |
|             isMinuteStepValid.value,
 | |
|             `\`minuteStep\` ${minuteStep} is invalid. It should be a factor of 60.`,
 | |
|           );
 | |
|           warning(
 | |
|             isSecondStepValid.value,
 | |
|             `\`secondStep\` ${secondStep} is invalid. It should be a factor of 60.`,
 | |
|           );
 | |
|         });
 | |
|       }
 | |
| 
 | |
|       const panelContext = useInjectPanel();
 | |
|       const {
 | |
|         operationRef,
 | |
|         panelRef: panelDivRef,
 | |
|         onSelect: onContextSelect,
 | |
|         hideRanges,
 | |
|         defaultOpenValue,
 | |
|       } = panelContext;
 | |
|       const { inRange, panelPosition, rangedValue, hoverRangedValue } = useInjectRange();
 | |
|       const panelRef = ref<PanelRefProps>({});
 | |
|       // Value
 | |
|       const [mergedValue, setInnerValue] = useMergedState<DateType | null>(null, {
 | |
|         value: toRef(props, 'value'),
 | |
|         defaultValue: props.defaultValue,
 | |
|         postState: val => {
 | |
|           if (!val && defaultOpenValue?.value && props.picker === 'time') {
 | |
|             return defaultOpenValue.value;
 | |
|           }
 | |
|           return val;
 | |
|         },
 | |
|       });
 | |
| 
 | |
|       // View date control
 | |
|       const [viewDate, setInnerViewDate] = useMergedState<DateType | null>(null, {
 | |
|         value: toRef(props, 'pickerValue'),
 | |
|         defaultValue: props.defaultPickerValue || mergedValue.value,
 | |
|         postState: date => {
 | |
|           const { generateConfig, showTime, defaultValue } = props;
 | |
|           const now = generateConfig.getNow();
 | |
|           if (!date) return now;
 | |
|           // When value is null and set showTime
 | |
|           if (!mergedValue.value && props.showTime) {
 | |
|             if (typeof showTime === 'object') {
 | |
|               return setDateTime(generateConfig, date, showTime.defaultValue || now);
 | |
|             }
 | |
|             if (defaultValue) {
 | |
|               return setDateTime(generateConfig, date, defaultValue);
 | |
|             }
 | |
|             return setDateTime(generateConfig, date, now);
 | |
|           }
 | |
|           return date;
 | |
|         },
 | |
|       });
 | |
| 
 | |
|       const setViewDate = (date: DateType) => {
 | |
|         setInnerViewDate(date);
 | |
|         if (props.onPickerValueChange) {
 | |
|           props.onPickerValueChange(date);
 | |
|         }
 | |
|       };
 | |
| 
 | |
|       // Panel control
 | |
|       const getInternalNextMode = (nextMode: PanelMode): PanelMode => {
 | |
|         const getNextMode = PickerModeMap[props.picker!];
 | |
|         if (getNextMode) {
 | |
|           return getNextMode(nextMode);
 | |
|         }
 | |
| 
 | |
|         return nextMode;
 | |
|       };
 | |
| 
 | |
|       // Save panel is changed from which panel
 | |
|       const [mergedMode, setInnerMode] = useMergedState(
 | |
|         () => {
 | |
|           if (props.picker === 'time') {
 | |
|             return 'time';
 | |
|           }
 | |
|           return getInternalNextMode('date');
 | |
|         },
 | |
|         {
 | |
|           value: toRef(props, 'mode'),
 | |
|         },
 | |
|       );
 | |
|       watch(
 | |
|         () => props.picker,
 | |
|         () => {
 | |
|           setInnerMode(props.picker);
 | |
|         },
 | |
|       );
 | |
| 
 | |
|       const sourceMode = ref(mergedMode.value);
 | |
|       const setSourceMode = (val: PanelMode) => {
 | |
|         sourceMode.value = val;
 | |
|       };
 | |
| 
 | |
|       const onInternalPanelChange = (newMode: PanelMode | null, viewValue: DateType) => {
 | |
|         const { onPanelChange, generateConfig } = props;
 | |
|         const nextMode = getInternalNextMode(newMode || mergedMode.value);
 | |
|         setSourceMode(mergedMode.value);
 | |
|         setInnerMode(nextMode);
 | |
| 
 | |
|         if (
 | |
|           onPanelChange &&
 | |
|           (mergedMode.value !== nextMode || isEqual(generateConfig, viewDate.value, viewDate.value))
 | |
|         ) {
 | |
|           onPanelChange(viewValue, nextMode);
 | |
|         }
 | |
|       };
 | |
| 
 | |
|       const triggerSelect = (
 | |
|         date: DateType,
 | |
|         type: 'key' | 'mouse' | 'submit',
 | |
|         forceTriggerSelect = false,
 | |
|       ) => {
 | |
|         const { picker, generateConfig, onSelect, onChange, disabledDate } = props;
 | |
|         if (mergedMode.value === picker || forceTriggerSelect) {
 | |
|           setInnerValue(date);
 | |
| 
 | |
|           if (onSelect) {
 | |
|             onSelect(date);
 | |
|           }
 | |
| 
 | |
|           if (onContextSelect) {
 | |
|             onContextSelect(date, type);
 | |
|           }
 | |
| 
 | |
|           if (
 | |
|             onChange &&
 | |
|             !isEqual(generateConfig, date, mergedValue.value) &&
 | |
|             !disabledDate?.(date)
 | |
|           ) {
 | |
|             onChange(date);
 | |
|           }
 | |
|         }
 | |
|       };
 | |
| 
 | |
|       // ========================= Interactive ==========================
 | |
|       const onInternalKeydown = (e: KeyboardEvent) => {
 | |
|         if (panelRef.value && panelRef.value.onKeydown) {
 | |
|           if (
 | |
|             [
 | |
|               KeyCode.LEFT,
 | |
|               KeyCode.RIGHT,
 | |
|               KeyCode.UP,
 | |
|               KeyCode.DOWN,
 | |
|               KeyCode.PAGE_UP,
 | |
|               KeyCode.PAGE_DOWN,
 | |
|               KeyCode.ENTER,
 | |
|             ].includes(e.which)
 | |
|           ) {
 | |
|             e.preventDefault();
 | |
|           }
 | |
|           return panelRef.value.onKeydown(e);
 | |
|         }
 | |
| 
 | |
|         /* istanbul ignore next */
 | |
|         /* eslint-disable no-lone-blocks */
 | |
|         {
 | |
|           warning(
 | |
|             false,
 | |
|             'Panel not correct handle keyDown event. Please help to fire issue about this.',
 | |
|           );
 | |
|           return false;
 | |
|         }
 | |
|         /* eslint-enable no-lone-blocks */
 | |
|       };
 | |
| 
 | |
|       const onInternalBlur = (e: FocusEvent) => {
 | |
|         if (panelRef.value && panelRef.value.onBlur) {
 | |
|           panelRef.value.onBlur(e);
 | |
|         }
 | |
|       };
 | |
|       const onNow = () => {
 | |
|         const { generateConfig, hourStep, minuteStep, secondStep } = props;
 | |
|         const now = generateConfig.getNow();
 | |
|         const lowerBoundTime = getLowerBoundTime(
 | |
|           generateConfig.getHour(now),
 | |
|           generateConfig.getMinute(now),
 | |
|           generateConfig.getSecond(now),
 | |
|           isHourStepValid.value ? hourStep : 1,
 | |
|           isMinuteStepValid.value ? minuteStep : 1,
 | |
|           isSecondStepValid.value ? secondStep : 1,
 | |
|         );
 | |
|         const adjustedNow = setTime(
 | |
|           generateConfig,
 | |
|           now,
 | |
|           lowerBoundTime[0], // hour
 | |
|           lowerBoundTime[1], // minute
 | |
|           lowerBoundTime[2], // second
 | |
|         );
 | |
|         triggerSelect(adjustedNow, 'submit');
 | |
|       };
 | |
| 
 | |
|       const classString = computed(() => {
 | |
|         const { prefixCls, direction } = props;
 | |
|         return classNames(`${prefixCls}-panel`, {
 | |
|           [`${prefixCls}-panel-has-range`]:
 | |
|             rangedValue && rangedValue.value && rangedValue.value[0] && rangedValue.value[1],
 | |
|           [`${prefixCls}-panel-has-range-hover`]:
 | |
|             hoverRangedValue &&
 | |
|             hoverRangedValue.value &&
 | |
|             hoverRangedValue.value[0] &&
 | |
|             hoverRangedValue.value[1],
 | |
|           [`${prefixCls}-panel-rtl`]: direction === 'rtl',
 | |
|         });
 | |
|       });
 | |
|       useProvidePanel({
 | |
|         ...panelContext,
 | |
|         mode: mergedMode,
 | |
|         hideHeader: computed(() =>
 | |
|           props.hideHeader !== undefined ? props.hideHeader : panelContext.hideHeader?.value,
 | |
|         ),
 | |
|         hidePrevBtn: computed(() => inRange.value && panelPosition.value === 'right'),
 | |
|         hideNextBtn: computed(() => inRange.value && panelPosition.value === 'left'),
 | |
|       });
 | |
| 
 | |
|       watch(
 | |
|         () => props.value,
 | |
|         () => {
 | |
|           if (props.value) {
 | |
|             setInnerViewDate(props.value);
 | |
|           }
 | |
|         },
 | |
|       );
 | |
| 
 | |
|       return () => {
 | |
|         const {
 | |
|           prefixCls = 'ant-picker',
 | |
|           locale,
 | |
|           generateConfig,
 | |
|           disabledDate,
 | |
|           picker = 'date',
 | |
|           tabindex = 0,
 | |
|           showNow,
 | |
|           showTime,
 | |
|           showToday,
 | |
|           renderExtraFooter,
 | |
|           onMousedown,
 | |
|           onOk,
 | |
|           components,
 | |
|         } = props;
 | |
|         if (operationRef && panelPosition.value !== 'right') {
 | |
|           operationRef.value = {
 | |
|             onKeydown: onInternalKeydown,
 | |
|             onClose: () => {
 | |
|               if (panelRef.value && panelRef.value.onClose) {
 | |
|                 panelRef.value.onClose();
 | |
|               }
 | |
|             },
 | |
|           };
 | |
|         }
 | |
| 
 | |
|         // ============================ Panels ============================
 | |
|         let panelNode: VueNode;
 | |
|         const pickerProps = {
 | |
|           ...attrs,
 | |
|           ...(props as MergedPickerPanelProps<DateType>),
 | |
|           operationRef: panelRef,
 | |
|           prefixCls,
 | |
|           viewDate: viewDate.value,
 | |
|           value: mergedValue.value,
 | |
|           onViewDateChange: setViewDate,
 | |
|           sourceMode: sourceMode.value,
 | |
|           onPanelChange: onInternalPanelChange,
 | |
|           disabledDate,
 | |
|         };
 | |
|         delete pickerProps.onChange;
 | |
|         delete pickerProps.onSelect;
 | |
|         switch (mergedMode.value) {
 | |
|           case 'decade':
 | |
|             panelNode = (
 | |
|               <DecadePanel<DateType>
 | |
|                 {...pickerProps}
 | |
|                 onSelect={(date, type) => {
 | |
|                   setViewDate(date);
 | |
|                   triggerSelect(date, type);
 | |
|                 }}
 | |
|               />
 | |
|             );
 | |
|             break;
 | |
| 
 | |
|           case 'year':
 | |
|             panelNode = (
 | |
|               <YearPanel<DateType>
 | |
|                 {...pickerProps}
 | |
|                 onSelect={(date, type) => {
 | |
|                   setViewDate(date);
 | |
|                   triggerSelect(date, type);
 | |
|                 }}
 | |
|               />
 | |
|             );
 | |
|             break;
 | |
| 
 | |
|           case 'month':
 | |
|             panelNode = (
 | |
|               <MonthPanel<DateType>
 | |
|                 {...pickerProps}
 | |
|                 onSelect={(date, type) => {
 | |
|                   setViewDate(date);
 | |
|                   triggerSelect(date, type);
 | |
|                 }}
 | |
|               />
 | |
|             );
 | |
|             break;
 | |
| 
 | |
|           case 'quarter':
 | |
|             panelNode = (
 | |
|               <QuarterPanel<DateType>
 | |
|                 {...pickerProps}
 | |
|                 onSelect={(date, type) => {
 | |
|                   setViewDate(date);
 | |
|                   triggerSelect(date, type);
 | |
|                 }}
 | |
|               />
 | |
|             );
 | |
|             break;
 | |
| 
 | |
|           case 'week':
 | |
|             panelNode = (
 | |
|               <WeekPanel
 | |
|                 {...pickerProps}
 | |
|                 onSelect={(date, type) => {
 | |
|                   setViewDate(date);
 | |
|                   triggerSelect(date, type);
 | |
|                 }}
 | |
|               />
 | |
|             );
 | |
|             break;
 | |
| 
 | |
|           case 'time':
 | |
|             delete pickerProps.showTime;
 | |
|             panelNode = (
 | |
|               <TimePanel<DateType>
 | |
|                 {...pickerProps}
 | |
|                 {...(typeof showTime === 'object' ? showTime : null)}
 | |
|                 onSelect={(date, type) => {
 | |
|                   setViewDate(date);
 | |
|                   triggerSelect(date, type);
 | |
|                 }}
 | |
|               />
 | |
|             );
 | |
|             break;
 | |
| 
 | |
|           default:
 | |
|             if (showTime) {
 | |
|               panelNode = (
 | |
|                 <DatetimePanel
 | |
|                   {...pickerProps}
 | |
|                   onSelect={(date, type) => {
 | |
|                     setViewDate(date);
 | |
|                     triggerSelect(date, type);
 | |
|                   }}
 | |
|                 />
 | |
|               );
 | |
|             } else {
 | |
|               panelNode = (
 | |
|                 <DatePanel<DateType>
 | |
|                   {...pickerProps}
 | |
|                   onSelect={(date, type) => {
 | |
|                     setViewDate(date);
 | |
|                     triggerSelect(date, type);
 | |
|                   }}
 | |
|                 />
 | |
|               );
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // ============================ Footer ============================
 | |
|         let extraFooter: VueNode;
 | |
|         let rangesNode: VueNode;
 | |
| 
 | |
|         if (!hideRanges?.value) {
 | |
|           extraFooter = getExtraFooter(prefixCls, mergedMode.value, renderExtraFooter);
 | |
|           rangesNode = getRanges({
 | |
|             prefixCls,
 | |
|             components,
 | |
|             needConfirmButton: needConfirmButton.value,
 | |
|             okDisabled: !mergedValue.value || (disabledDate && disabledDate(mergedValue.value)),
 | |
|             locale,
 | |
|             showNow,
 | |
|             onNow: needConfirmButton.value && onNow,
 | |
|             onOk: () => {
 | |
|               if (mergedValue.value) {
 | |
|                 triggerSelect(mergedValue.value, 'submit', true);
 | |
|                 if (onOk) {
 | |
|                   onOk(mergedValue.value);
 | |
|                 }
 | |
|               }
 | |
|             },
 | |
|           });
 | |
|         }
 | |
| 
 | |
|         let todayNode: VueNode;
 | |
| 
 | |
|         if (showToday && mergedMode.value === 'date' && picker === 'date' && !showTime) {
 | |
|           const now = generateConfig.getNow();
 | |
|           const todayCls = `${prefixCls}-today-btn`;
 | |
|           const disabled = disabledDate && disabledDate(now);
 | |
|           todayNode = (
 | |
|             <a
 | |
|               class={classNames(todayCls, disabled && `${todayCls}-disabled`)}
 | |
|               aria-disabled={disabled}
 | |
|               onClick={() => {
 | |
|                 if (!disabled) {
 | |
|                   triggerSelect(now, 'mouse', true);
 | |
|                 }
 | |
|               }}
 | |
|             >
 | |
|               {locale.today}
 | |
|             </a>
 | |
|           );
 | |
|         }
 | |
|         return (
 | |
|           <div
 | |
|             tabindex={tabindex}
 | |
|             class={classNames(classString.value, attrs.class)}
 | |
|             style={attrs.style}
 | |
|             onKeydown={onInternalKeydown}
 | |
|             onBlur={onInternalBlur}
 | |
|             onMousedown={onMousedown}
 | |
|             ref={panelDivRef}
 | |
|           >
 | |
|             {panelNode}
 | |
|             {extraFooter || rangesNode || todayNode ? (
 | |
|               <div class={`${prefixCls}-footer`}>
 | |
|                 {extraFooter}
 | |
|                 {rangesNode}
 | |
|                 {todayNode}
 | |
|               </div>
 | |
|             ) : null}
 | |
|           </div>
 | |
|         );
 | |
|       };
 | |
|     },
 | |
|   });
 | |
| }
 | |
| const InterPickerPanel = PickerPanel<any>();
 | |
| export default <DateType extends any>(props: MergedPickerPanelProps<DateType>): JSX.Element =>
 | |
|   createVNode(InterPickerPanel, props);
 |