feat: datepicker timepicker calendar support string value #718

pull/2184/head
tanjinzhou 2020-04-29 18:44:11 +08:00
parent a28962bfe7
commit ed528e68b7
13 changed files with 184 additions and 118 deletions

View File

@ -0,0 +1,75 @@
import interopDefault from './interopDefault';
import * as moment from 'moment';
import warning from './warning';
import isNil from 'lodash/isNil';
export const TimeType = {
validator(value) {
return typeof value === 'string' || isNil(value) || moment.isMoment(value);
},
};
export const TimesType = {
validator(value) {
if (Array.isArray(value)) {
return (
value.length === 0 ||
value.findIndex(val => typeof val !== 'string') === -1 ||
value.findIndex(val => !isNil(val) && !moment.isMoment(val)) === -1
);
}
return false;
},
};
export const TimeOrTimesType = {
validator(value) {
if (Array.isArray(value)) {
return (
value.length === 0 ||
value.findIndex(val => typeof val !== 'string') === -1 ||
value.findIndex(val => !isNil(val) && !moment.isMoment(val)) === -1
);
} else {
return typeof value === 'string' || isNil(value) || moment.isMoment(value);
}
},
};
export function checkValidate(componentName, value, propName, valueFormat) {
const values = Array.isArray(value) ? value : [value];
values.forEach(val => {
if (!val) return;
valueFormat &&
warning(
interopDefault(moment)(val, valueFormat).isValid(),
componentName,
`When set \`valueFormat\`, \`${propName}\` should provides invalidate string time. `,
);
!valueFormat &&
warning(
interopDefault(moment).isMoment(val) && val.isValid(),
componentName,
`\`${propName}\` provides invalidate moment time. If you want to set empty value, use \`null\` instead.`,
);
});
}
export const stringToMoment = (value, valueFormat) => {
if (Array.isArray(value)) {
return value.map(val =>
typeof val === 'string' && val ? interopDefault(moment)(val, valueFormat) : val || null,
);
} else {
return typeof value === 'string' && value
? interopDefault(moment)(value, valueFormat)
: value || null;
}
};
export const momentToString = (value, valueFormat) => {
if (Array.isArray(value)) {
return value.map(val => (interopDefault(moment).isMoment(val) ? val.format(valueFormat) : val));
} else {
return interopDefault(moment).isMoment(value) ? value.format(valueFormat) : value;
}
};

View File

@ -9,6 +9,7 @@ import interopDefault from '../_util/interopDefault';
import { ConfigConsumerProps } from '../config-provider';
import enUS from './locale/en_US';
import Base from '../base';
import { checkValidate, stringToMoment, momentToString, TimeType } from '../_util/moment-util';
function noop() {
return null;
@ -20,12 +21,6 @@ function zerofixed(v) {
}
return `${v}`;
}
export const MomentType = {
type: Object,
validator(value) {
return moment.isMoment(value);
},
};
function isMomentArray(value) {
return Array.isArray(value) && !!value.find(val => moment.isMoment(val));
}
@ -33,8 +28,8 @@ export const CalendarMode = PropTypes.oneOf(['month', 'year']);
export const CalendarProps = () => ({
prefixCls: PropTypes.string,
value: MomentType,
defaultValue: MomentType,
value: TimeType,
defaultValue: TimeType,
mode: CalendarMode,
fullscreen: PropTypes.bool,
// dateCellRender: PropTypes.func,
@ -47,6 +42,7 @@ export const CalendarProps = () => ({
disabledDate: PropTypes.func,
validRange: PropTypes.custom(isMomentArray),
headerRender: PropTypes.func,
valueFormat: PropTypes.string,
});
const Calendar = {
@ -64,20 +60,21 @@ const Calendar = {
configProvider: { default: () => ConfigConsumerProps },
},
data() {
const value = this.value || this.defaultValue || interopDefault(moment)();
if (!interopDefault(moment).isMoment(value)) {
throw new Error('The value/defaultValue of Calendar must be a moment object, ');
}
const { value, defaultValue, valueFormat } = this;
const sValue = value || defaultValue || interopDefault(moment)();
checkValidate('Calendar', defaultValue, 'defaultValue', valueFormat);
checkValidate('Calendar', value, 'value', valueFormat);
this._sPrefixCls = undefined;
return {
sValue: value,
sValue: stringToMoment(sValue, valueFormat),
sMode: this.mode || 'month',
};
},
watch: {
value(val) {
checkValidate('Calendar', val, 'value', this.valueFormat);
this.setState({
sValue: val,
sValue: stringToMoment(val, this.valueFormat),
});
},
mode(val) {
@ -95,9 +92,10 @@ const Calendar = {
this.onPanelChange(this.sValue, mode);
},
onPanelChange(value, mode) {
this.$emit('panelChange', value, mode);
const val = this.valueFormat ? momentToString(value, this.valueFormat) : value;
this.$emit('panelChange', val, mode);
if (value !== this.sValue) {
this.$emit('change', value);
this.$emit('change', val);
}
},
@ -105,8 +103,8 @@ const Calendar = {
this.setValue(value, 'select');
},
setValue(value, way) {
const prevValue = this.value || this.sValue;
const { sMode: mode } = this;
const prevValue = this.value ? stringToMoment(this.value, this.valueFormat) : this.sValue;
const { sMode: mode, valueFormat } = this;
if (!hasProp(this, 'value')) {
this.setState({ sValue: value });
}
@ -114,7 +112,7 @@ const Calendar = {
if (prevValue && prevValue.month() !== value.month()) {
this.onPanelChange(value, mode);
}
this.$emit('select', value);
this.$emit('select', valueFormat ? momentToString(value, valueFormat) : value);
} else if (way === 'changePanel') {
this.onPanelChange(value, mode);
}

View File

@ -1,13 +1,6 @@
import * as moment from 'moment';
// import { TimePickerProps } from '../time-picker'
import PropTypes from '../_util/vue-types';
export const MomentType = {
type: Object,
validator(value) {
return value === undefined || moment.isMoment(value);
},
};
import { TimesType, TimeType } from '../_util/moment-util';
export const PickerProps = () => ({
name: PropTypes.string,
@ -37,12 +30,13 @@ export const PickerProps = () => ({
tabIndex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
align: PropTypes.object.def(() => ({})),
inputReadOnly: PropTypes.bool,
valueFormat: PropTypes.string,
});
export const SinglePickerProps = () => ({
value: MomentType,
defaultValue: MomentType,
defaultPickerValue: MomentType,
value: TimeType,
defaultValue: TimeType,
defaultPickerValue: TimeType,
renderExtraFooter: PropTypes.any,
placeholder: PropTypes.string,
// onChange?: (date: moment.Moment, dateString: string) => void;
@ -65,27 +59,17 @@ export const MonthPickerProps = () => ({
placeholder: PropTypes.string,
monthCellContentRender: PropTypes.func,
});
function isMomentArray(value) {
if (Array.isArray(value)) {
return (
value.length === 0 || value.findIndex(val => val === undefined || moment.isMoment(val)) !== -1
);
}
return false;
}
export const RangePickerValue = PropTypes.custom(isMomentArray);
// export const RangePickerPresetRange = PropTypes.oneOfType([RangePickerValue, PropTypes.func])
// export const RangePickerPresetRange = PropTypes.oneOfType([TimesType, PropTypes.func])
export const RangePickerProps = () => ({
...PickerProps(),
tagPrefixCls: PropTypes.string,
value: RangePickerValue,
defaultValue: RangePickerValue,
defaultPickerValue: RangePickerValue,
value: TimesType,
defaultValue: TimesType,
defaultPickerValue: TimesType,
timePicker: PropTypes.any,
// onChange?: (dates: RangePickerValue, dateStrings: [string, string]) => void;
// onCalendarChange?: (dates: RangePickerValue, dateStrings: [string, string]) => void;
// onChange?: (dates: TimesType, dateStrings: [string, string]) => void;
// onCalendarChange?: (dates: TimesType, dateStrings: [string, string]) => void;
// onOk?: (selectedTime: moment.Moment) => void;
showTime: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
ranges: PropTypes.object,
@ -95,7 +79,7 @@ export const RangePickerProps = () => ({
disabledTime: PropTypes.func,
showToday: PropTypes.bool,
renderExtraFooter: PropTypes.any,
// onPanelChange?: (value?: RangePickerValue, mode?: string | string[]) => void;
// onPanelChange?: (value?: TimesType, mode?: string | string[]) => void;
});
export const WeekPickerProps = () => ({

View File

@ -1,26 +1,11 @@
import TimePickerPanel from '../vc-time-picker/Panel';
import classNames from 'classnames';
import * as moment from 'moment';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { generateShowHourMinuteSecond } from '../time-picker';
import enUS from './locale/en_US';
import interopDefault from '../_util/interopDefault';
import { getOptionProps, initDefaultProps, getListeners } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
function checkValidate(value, propName) {
const values = Array.isArray(value) ? value : [value];
values.forEach(val => {
if (!val) return;
warning(
!interopDefault(moment).isMoment(val) || val.isValid(),
'DatePicker',
`\`${propName}\` provides invalidate moment time. If you want to set empty value, use \`null\` instead.`,
);
});
}
import { checkValidate, stringToMoment, momentToString } from '../_util/moment-util';
const DEFAULT_FORMAT = {
date: 'YYYY-MM-DD',
@ -74,9 +59,9 @@ export default function wrapPicker(Picker, props, pickerType) {
};
},
mounted() {
const { autoFocus, disabled, value, defaultValue } = this;
checkValidate(defaultValue, 'defaultValue');
checkValidate(value, 'value');
const { autoFocus, disabled, value, defaultValue, valueFormat } = this;
checkValidate('DatePicker', defaultValue, 'defaultValue', valueFormat);
checkValidate('DatePicker', value, 'value', valueFormat);
if (autoFocus && !disabled) {
this.$nextTick(() => {
this.focus();
@ -85,7 +70,7 @@ export default function wrapPicker(Picker, props, pickerType) {
},
watch: {
value(val) {
checkValidate(val, 'value');
checkValidate('DatePicker', val, 'value', this.valueFormat);
},
},
methods: {
@ -123,7 +108,13 @@ export default function wrapPicker(Picker, props, pickerType) {
handleMouseLeave(e) {
this.$emit('mouseleave', e);
},
handleChange(date, dateString) {
this.$emit(
'change',
this.valueFormat ? momentToString(date, this.valueFormat) : date,
dateString,
);
},
focus() {
this.$refs.picker.focus();
},
@ -132,8 +123,21 @@ export default function wrapPicker(Picker, props, pickerType) {
this.$refs.picker.blur();
},
transformValue(props) {
if ('value' in props) {
props.value = stringToMoment(props.value, this.valueFormat);
}
if ('defaultValue' in props) {
props.defaultValue = stringToMoment(props.defaultValue, this.valueFormat);
}
if ('defaultPickerValue' in props) {
props.defaultPickerValue = stringToMoment(props.defaultPickerValue, this.valueFormat);
}
},
renderPicker(locale, localeCode) {
const props = getOptionProps(this);
this.transformValue(props);
const {
prefixCls: customizePrefixCls,
inputPrefixCls: customizeInputPrefixCls,
@ -203,6 +207,7 @@ export default function wrapPicker(Picker, props, pickerType) {
blur: this.handleBlur,
mouseenter: this.handleMouseEnter,
mouseleave: this.handleMouseLeave,
change: this.handleChange,
},
ref: 'picker',
scopedSlots: this.$scopedSlots || {},

View File

@ -1,4 +1,3 @@
import * as moment from 'moment';
import omit from 'omit.js';
import VcTimePicker from '../vc-time-picker';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
@ -7,7 +6,6 @@ import PropTypes from '../_util/vue-types';
import warning from '../_util/warning';
import Icon from '../icon';
import enUS from './locale/en_US';
import interopDefault from '../_util/interopDefault';
import {
initDefaultProps,
hasProp,
@ -19,6 +17,12 @@ import {
import { cloneElement } from '../_util/vnode';
import { ConfigConsumerProps } from '../config-provider';
import Base from '../base';
import {
checkValidate,
stringToMoment,
momentToString,
TimeOrTimesType,
} from '../_util/moment-util';
export function generateShowHourMinuteSecond(format) {
// Ref: http://momentjs.com/docs/#/parsing/string-format/
@ -28,20 +32,11 @@ export function generateShowHourMinuteSecond(format) {
showSecond: format.indexOf('s') > -1,
};
}
function isMoment(value) {
if (Array.isArray(value)) {
return (
value.length === 0 || value.findIndex(val => val === undefined || moment.isMoment(val)) !== -1
);
} else {
return value === undefined || moment.isMoment(value);
}
}
const MomentType = PropTypes.custom(isMoment);
export const TimePickerProps = () => ({
size: PropTypes.oneOf(['large', 'default', 'small']),
value: MomentType,
defaultValue: MomentType,
value: TimeOrTimesType,
defaultValue: TimeOrTimesType,
open: PropTypes.bool,
format: PropTypes.string,
disabled: PropTypes.bool,
@ -72,6 +67,7 @@ export const TimePickerProps = () => ({
addon: PropTypes.any,
clearIcon: PropTypes.any,
locale: PropTypes.object,
valueFormat: PropTypes.string,
});
const TimePicker = {
@ -104,22 +100,23 @@ const TimePicker = {
configProvider: { default: () => ConfigConsumerProps },
},
data() {
const value = this.value || this.defaultValue;
if (value && !interopDefault(moment).isMoment(value)) {
throw new Error('The value/defaultValue of TimePicker must be a moment object, ');
}
const { value, defaultValue, valueFormat } = this;
checkValidate('TimePicker', defaultValue, 'defaultValue', valueFormat);
checkValidate('TimePicker', value, 'value', valueFormat);
warning(
!hasProp(this, 'allowEmpty'),
'TimePicker',
'`allowEmpty` is deprecated. Please use `allowClear` instead.',
);
return {
sValue: value,
sValue: stringToMoment(value || defaultValue, valueFormat),
};
},
watch: {
value(val) {
this.setState({ sValue: val });
checkValidate('TimePicker', val, 'value', this.valueFormat);
this.setState({ sValue: stringToMoment(val, this.valueFormat) });
},
},
methods: {
@ -155,7 +152,11 @@ const TimePicker = {
this.setState({ sValue: value });
}
const { format = 'HH:mm:ss' } = this;
this.$emit('change', value, (value && value.format(format)) || '');
this.$emit(
'change',
this.valueFormat ? momentToString(value, this.valueFormat) : value,
(value && value.format(format)) || '',
);
},
handleOpenClose({ open }) {

View File

@ -7,17 +7,18 @@ import KeyCode from '../../_util/KeyCode';
import placements from './picker/placements';
import Trigger from '../../vc-trigger';
import moment from 'moment';
import { setTimeout } from 'timers';
function isMoment(value) {
if (Array.isArray(value)) {
return (
value.length === 0 || value.findIndex(val => val === undefined || moment.isMoment(val)) !== -1
);
} else {
return value === undefined || moment.isMoment(value);
}
}
const MomentType = PropTypes.custom(isMoment);
import isNil from 'lodash/isNil';
const TimeType = {
validator(value) {
if (Array.isArray(value)) {
return (
value.length === 0 || value.findIndex(val => !isNil(val) && !moment.isMoment(val)) === -1
);
} else {
return isNil(value) || moment.isMoment(value);
}
},
};
const Picker = {
name: 'Picker',
props: {
@ -34,8 +35,8 @@ const Picker = {
defaultOpen: PropTypes.bool.def(false),
prefixCls: PropTypes.string.def('rc-calendar-picker'),
placement: PropTypes.any.def('bottomLeft'),
value: PropTypes.oneOfType([MomentType, PropTypes.arrayOf(MomentType)]),
defaultValue: PropTypes.oneOfType([MomentType, PropTypes.arrayOf(MomentType)]),
value: TimeType,
defaultValue: TimeType,
align: PropTypes.object.def(() => ({})),
dropdownClassName: PropTypes.string,
dateRender: PropTypes.func,

5
types/calendar.d.ts vendored
View File

@ -31,7 +31,7 @@ export declare class Calendar extends AntdComponent {
* @default default date
* @type Moment
*/
defaultValue: Moment;
defaultValue: Moment | string;
/**
* Function that specifies the dates that cannot be selected
@ -84,5 +84,6 @@ export declare class Calendar extends AntdComponent {
* @default current date
* @type Moment
*/
value: Moment;
value: Moment | string;
valueFormat: string;
}

View File

@ -88,4 +88,5 @@ export declare class DatepickerCommon extends AntdComponent {
suffixIcon: any;
inputReadOnly: boolean;
valueFormat: string;
}

View File

@ -19,7 +19,7 @@ export declare class DatePicker extends DatepickerCommon {
* @default undefined
* @type Moment
*/
defaultValue: Moment;
defaultValue: Moment | string;
/**
* Default Picker Value
@ -27,7 +27,7 @@ export declare class DatePicker extends DatepickerCommon {
* @default undefined
* @type Moment
*/
defaultPickerValue: Moment;
defaultPickerValue: Moment | string;
/**
* Disabled Time
@ -77,5 +77,5 @@ export declare class DatePicker extends DatepickerCommon {
* @default undefined
* @type Moment
*/
value: Moment;
value: Moment | string;
}

View File

@ -10,13 +10,13 @@ export declare class MonthPicker extends DatepickerCommon {
* to set default date
* @type Moment
*/
defaultValue: Moment;
defaultValue: Moment | string;
/**
* to set default picker date
* @type Moment
*/
defaultPickerValue: Moment;
defaultPickerValue: Moment | string;
/**
* to set the date format, When an array is provided, all values are used for parsing and first value for display. refer to moment.js
@ -42,5 +42,5 @@ export declare class MonthPicker extends DatepickerCommon {
* to set date
* @type Moment
*/
value: Moment;
value: Moment | string;
}

View File

@ -10,13 +10,13 @@ export declare class RangePicker extends DatepickerCommon {
* to set default date
* @type [Moment, Moment]
*/
defaultValue: [Moment, Moment];
defaultValue: [Moment, Moment] | [string, string];
/**
* to set default picker date
* @type [Moment, Moment]
*/
defaultPickerValue: [Moment, Moment];
defaultPickerValue: [Moment, Moment] | [string, string];
/**
* to specify the time that cannot be selected
@ -56,5 +56,5 @@ export declare class RangePicker extends DatepickerCommon {
* to set date
* @type [Moment, Moment]
*/
value: [Moment, Moment];
value: [Moment, Moment] | [string, string];
}

View File

@ -10,13 +10,13 @@ export declare class WeekPicker extends DatepickerCommon {
* to set default date
* @type Moment
*/
defaultValue: Moment;
defaultValue: Moment | string;
/**
* to set default picker date
* @type Moment
*/
defaultPickerValue: Moment;
defaultPickerValue: Moment | string;
/**
* to set the date format, refer to moment.js
@ -30,5 +30,5 @@ export declare class WeekPicker extends DatepickerCommon {
* to set date
* @type Moment
*/
value: Moment;
value: Moment | string;
}

View File

@ -44,7 +44,7 @@ export declare class TimePicker extends AntdComponent {
* to set default time
* @type Moment
*/
defaultValue: Moment;
defaultValue: Moment | string;
/**
* determine whether the TimePicker is disabled
@ -158,7 +158,7 @@ export declare class TimePicker extends AntdComponent {
* to set time
* @type Moment
*/
value: Moment;
value: Moment | string;
/**
* Time picker size