ant-design/components/date-picker/generatePicker/generateSinglePicker.tsx
2022-05-14 16:34:35 +08:00

169 lines
6.8 KiB
TypeScript

import * as React from 'react';
import classNames from 'classnames';
import CalendarOutlined from '@ant-design/icons/CalendarOutlined';
import ClockCircleOutlined from '@ant-design/icons/ClockCircleOutlined';
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import RCPicker from 'rc-picker';
import type { PickerMode } from 'rc-picker/lib/interface';
import type { GenerateConfig } from 'rc-picker/lib/generate/index';
import { forwardRef, useContext, useImperativeHandle } from 'react';
import enUS from '../locale/en_US';
import { getPlaceholder, transPlacement2DropdownAlign } from '../util';
import warning from '../../_util/warning';
import { ConfigContext } from '../../config-provider';
import LocaleReceiver from '../../locale-provider/LocaleReceiver';
import SizeContext from '../../config-provider/SizeContext';
import DisabledContext from '../../config-provider/DisabledContext';
import type { PickerProps, PickerLocale, PickerDateProps, PickerTimeProps } from '.';
import { getTimeProps, Components } from '.';
import { FormItemInputContext } from '../../form/context';
import type { InputStatus } from '../../_util/statusUtils';
import { getMergedStatus, getStatusClassNames } from '../../_util/statusUtils';
import type { DatePickRef, PickerComponentClass, CommonPickerMethods } from './interface';
export default function generatePicker<DateType>(generateConfig: GenerateConfig<DateType>) {
type DatePickerProps = PickerProps<DateType> & {
status?: InputStatus;
};
function getPicker<InnerPickerProps extends DatePickerProps>(
picker?: PickerMode,
displayName?: string,
) {
const Picker = forwardRef<DatePickRef<DateType> | CommonPickerMethods, InnerPickerProps>(
(props, ref) => {
const {
prefixCls: customizePrefixCls,
getPopupContainer: customizeGetPopupContainer,
className,
size: customizeSize,
bordered = true,
placement,
placeholder,
disabled: customDisabled,
status: customStatus,
...restProps
} = props;
warning(
picker !== 'quarter',
displayName!,
`DatePicker.${displayName} is legacy usage. Please use DatePicker[picker='${picker}'] directly.`,
);
const { getPrefixCls, direction, getPopupContainer } = useContext(ConfigContext);
const prefixCls = getPrefixCls('picker', customizePrefixCls);
const innerRef = React.useRef<RCPicker<DateType>>(null);
const { format, showTime } = props as any;
useImperativeHandle(ref, () => ({
focus: () => innerRef.current?.focus(),
blur: () => innerRef.current?.blur(),
}));
const additionalProps = {
showToday: true,
};
let additionalOverrideProps: any = {};
if (picker) {
additionalOverrideProps.picker = picker;
}
const mergedPicker = picker || props.picker;
additionalOverrideProps = {
...additionalOverrideProps,
...(showTime ? getTimeProps({ format, picker: mergedPicker, ...showTime }) : {}),
...(mergedPicker === 'time'
? getTimeProps({ format, ...props, picker: mergedPicker })
: {}),
};
const rootPrefixCls = getPrefixCls();
// ===================== Size =====================
const size = React.useContext(SizeContext);
const mergedSize = customizeSize || size;
// ===================== Disabled =====================
const disabled = React.useContext(DisabledContext);
const mergedDisabled = customDisabled || disabled;
// ===================== FormItemInput =====================
const formItemContext = useContext(FormItemInputContext);
const { hasFeedback, status: contextStatus, feedbackIcon } = formItemContext;
const suffixNode = (
<>
{mergedPicker === 'time' ? <ClockCircleOutlined /> : <CalendarOutlined />}
{hasFeedback && feedbackIcon}
</>
);
return (
<LocaleReceiver componentName="DatePicker" defaultLocale={enUS}>
{(contextLocale: PickerLocale) => {
const locale = { ...contextLocale, ...props.locale };
return (
<RCPicker<DateType>
ref={innerRef}
placeholder={getPlaceholder(mergedPicker, locale, placeholder)}
suffixIcon={suffixNode}
dropdownAlign={transPlacement2DropdownAlign(direction, placement)}
clearIcon={<CloseCircleFilled />}
prevIcon={<span className={`${prefixCls}-prev-icon`} />}
nextIcon={<span className={`${prefixCls}-next-icon`} />}
superPrevIcon={<span className={`${prefixCls}-super-prev-icon`} />}
superNextIcon={<span className={`${prefixCls}-super-next-icon`} />}
allowClear
transitionName={`${rootPrefixCls}-slide-up`}
{...additionalProps}
{...restProps}
{...additionalOverrideProps}
locale={locale!.lang}
className={classNames(
{
[`${prefixCls}-${mergedSize}`]: mergedSize,
[`${prefixCls}-borderless`]: !bordered,
},
getStatusClassNames(
prefixCls as string,
getMergedStatus(contextStatus, customStatus),
hasFeedback,
),
className,
)}
prefixCls={prefixCls}
getPopupContainer={customizeGetPopupContainer || getPopupContainer}
generateConfig={generateConfig}
components={Components}
direction={direction}
disabled={mergedDisabled}
/>
);
}}
</LocaleReceiver>
);
},
);
if (displayName) {
Picker.displayName = displayName;
}
return Picker as unknown as PickerComponentClass<InnerPickerProps>;
}
const DatePicker = getPicker<DatePickerProps>();
const WeekPicker = getPicker<Omit<PickerDateProps<DateType>, 'picker'>>('week', 'WeekPicker');
const MonthPicker = getPicker<Omit<PickerDateProps<DateType>, 'picker'>>('month', 'MonthPicker');
const YearPicker = getPicker<Omit<PickerDateProps<DateType>, 'picker'>>('year', 'YearPicker');
const TimePicker = getPicker<Omit<PickerTimeProps<DateType>, 'picker'>>('time', 'TimePicker');
const QuarterPicker = getPicker<Omit<PickerTimeProps<DateType>, 'picker'>>(
'quarter',
'QuarterPicker',
);
return { DatePicker, WeekPicker, MonthPicker, YearPicker, TimePicker, QuarterPicker };
}