refactor: date-picker by ts

pull/2992/head
tangjinzhou 2020-10-14 23:12:51 +08:00
parent db31c526d9
commit 54ca9021c3
12 changed files with 249 additions and 191 deletions

View File

@ -1,7 +1,7 @@
import { VueTypeValidableDef, VueTypeDef } from 'vue-types'; import { VueTypeValidableDef, VueTypeDef } from 'vue-types';
const initDefaultProps = <T>( const initDefaultProps = <T>(
propTypes: T, types: T,
defaultProps: { defaultProps: {
[K in keyof T]?: T[K] extends VueTypeValidableDef<infer U> [K in keyof T]?: T[K] extends VueTypeValidableDef<infer U>
? U ? U
@ -10,6 +10,7 @@ const initDefaultProps = <T>(
: any; : any;
}, },
): T => { ): T => {
const propTypes = { ...types };
Object.keys(defaultProps).forEach(k => { Object.keys(defaultProps).forEach(k => {
const prop = propTypes[k] as VueTypeValidableDef; const prop = propTypes[k] as VueTypeValidableDef;
if (prop) { if (prop) {

View File

@ -3,7 +3,7 @@ import { isValidElement } from '../_util/props-util';
import { cloneElement } from '../_util/vnode'; import { cloneElement } from '../_util/vnode';
import classNames from '../_util/classNames'; import classNames from '../_util/classNames';
const InputIcon = (_, { attrs }) => { const InputIcon = (_: any, { attrs }) => {
const { suffixIcon, prefixCls } = attrs; const { suffixIcon, prefixCls } = attrs;
return ( return (
(suffixIcon && isValidElement(suffixIcon) ? ( (suffixIcon && isValidElement(suffixIcon) ? (

View File

@ -1,4 +1,4 @@
import { inject } from 'vue'; import { CSSProperties, defineComponent, inject } from 'vue';
import moment from 'moment'; import moment from 'moment';
import RangeCalendar from '../vc-calendar/src/RangeCalendar'; import RangeCalendar from '../vc-calendar/src/RangeCalendar';
import VcDatePicker from '../vc-calendar/src/Picker'; import VcDatePicker from '../vc-calendar/src/Picker';
@ -9,26 +9,40 @@ import Tag from '../tag';
import { defaultConfigProvider } from '../config-provider'; import { defaultConfigProvider } from '../config-provider';
import interopDefault from '../_util/interopDefault'; import interopDefault from '../_util/interopDefault';
import { RangePickerProps } from './interface'; import { RangePickerProps } from './interface';
import { hasProp, getOptionProps, initDefaultProps, getComponent } from '../_util/props-util'; import { hasProp, getOptionProps, getComponent } from '../_util/props-util';
import BaseMixin from '../_util/BaseMixin'; import BaseMixin from '../_util/BaseMixin';
import { formatDate } from './utils'; import { formatDate } from './utils';
import InputIcon from './InputIcon'; import InputIcon from './InputIcon';
import { getDataAndAriaProps } from '../_util/util'; import { getDataAndAriaProps } from '../_util/util';
import initDefaultProps from '../_util/props-util/initDefaultProps';
function getShowDateFromValue(value, mode) { type RangePickerValue =
| undefined[]
| null[]
| [moment.Moment]
| [undefined, moment.Moment]
| [moment.Moment, undefined]
| [null, moment.Moment]
| [moment.Moment, null]
| [moment.Moment, moment.Moment];
export type RangePickerPresetRange = RangePickerValue | (() => RangePickerValue);
function getShowDateFromValue(value: RangePickerValue, mode?: string | string[]) {
const [start, end] = value; const [start, end] = value;
// value could be an empty array, then we should not reset showDate // value could be an empty array, then we should not reset showDate
if (!start && !end) { if (!start && !end) {
return; return;
} }
if (mode && mode[0] === 'month') { if (mode && mode[0] === 'month') {
return [start, end]; return [start, end] as RangePickerValue;
} }
const newEnd = end && end.isSame(start, 'month') ? end.clone().add(1, 'month') : end; const newEnd = end && end.isSame(start, 'month') ? end.clone().add(1, 'month') : end;
return [start, newEnd]; return [start, newEnd] as RangePickerValue;
} }
function pickerValueAdapter(value) { function pickerValueAdapter(
value?: moment.Moment | RangePickerValue,
): RangePickerValue | undefined {
if (!value) { if (!value) {
return; return;
} }
@ -38,14 +52,14 @@ function pickerValueAdapter(value) {
return [value, value.clone().add(1, 'month')]; return [value, value.clone().add(1, 'month')];
} }
function isEmptyArray(arr) { function isEmptyArray(arr: any) {
if (Array.isArray(arr)) { if (Array.isArray(arr)) {
return arr.length === 0 || arr.every(i => !i); return arr.length === 0 || arr.every(i => !i);
} }
return false; return false;
} }
function fixLocale(value, localeCode) { function fixLocale(value: RangePickerValue | undefined, localeCode: string | undefined) {
if (!localeCode) { if (!localeCode) {
return; return;
} }
@ -61,11 +75,18 @@ function fixLocale(value, localeCode) {
} }
} }
export default { export interface RangePickerState {
sValue?: RangePickerValue;
sShowDate?: RangePickerValue;
sOpen?: boolean;
sHoverValue?: RangePickerValue;
}
export default defineComponent({
name: 'ARangePicker', name: 'ARangePicker',
mixins: [BaseMixin], mixins: [BaseMixin],
inheritAttrs: false, inheritAttrs: false,
props: initDefaultProps(RangePickerProps(), { props: initDefaultProps(RangePickerProps, {
allowClear: true, allowClear: true,
showToday: false, showToday: false,
separator: '~', separator: '~',
@ -73,9 +94,12 @@ export default {
setup() { setup() {
return { return {
configProvider: inject('configProvider', defaultConfigProvider), configProvider: inject('configProvider', defaultConfigProvider),
picker: null,
sTagPrefixCls: undefined,
sPrefixCls: '',
}; };
}, },
data() { data(): RangePickerState {
const value = this.value || this.defaultValue || []; const value = this.value || this.defaultValue || [];
const [start, end] = value; const [start, end] = value;
if ( if (
@ -89,7 +113,7 @@ export default {
} }
const pickerValue = !value || isEmptyArray(value) ? this.defaultPickerValue : value; const pickerValue = !value || isEmptyArray(value) ? this.defaultPickerValue : value;
return { return {
sValue: value, sValue: value as RangePickerValue,
sShowDate: pickerValueAdapter(pickerValue || interopDefault(moment)()), sShowDate: pickerValueAdapter(pickerValue || interopDefault(moment)()),
sOpen: this.open, sOpen: this.open,
sHoverValue: [], sHoverValue: [],
@ -98,7 +122,7 @@ export default {
watch: { watch: {
value(val) { value(val) {
const value = val || []; const value = val || [];
let state = { sValue: value }; let state: RangePickerState = { sValue: value };
if (!shallowequal(val, this.sValue)) { if (!shallowequal(val, this.sValue)) {
state = { state = {
...state, ...state,
@ -120,14 +144,14 @@ export default {
}, },
}, },
methods: { methods: {
setValue(value, hidePanel) { setValue(value: RangePickerValue, hidePanel?: boolean) {
this.handleChange(value); this.handleChange(value);
if ((hidePanel || !this.showTime) && !hasProp(this, 'open')) { if ((hidePanel || !this.showTime) && !hasProp(this, 'open')) {
this.setState({ sOpen: false }); this.setState({ sOpen: false });
} }
}, },
savePicker(node) { savePicker(node: any) {
this.picker = node; this.picker = node;
}, },
clearSelection(e) { clearSelection(e) {
@ -141,7 +165,7 @@ export default {
this.setState({ sHoverValue: [] }); this.setState({ sHoverValue: [] });
}, },
handleChange(value) { handleChange(value: RangePickerValue) {
if (!hasProp(this, 'value')) { if (!hasProp(this, 'value')) {
this.setState(({ sShowDate }) => ({ this.setState(({ sShowDate }) => ({
sValue: value, sValue: value,
@ -155,7 +179,7 @@ export default {
this.$emit('change', value, [formatDate(start, this.format), formatDate(end, this.format)]); this.$emit('change', value, [formatDate(start, this.format), formatDate(end, this.format)]);
}, },
handleOpenChange(open) { handleOpenChange(open: boolean) {
if (!hasProp(this, 'open')) { if (!hasProp(this, 'open')) {
this.setState({ sOpen: open }); this.setState({ sOpen: open });
} }
@ -166,11 +190,11 @@ export default {
this.$emit('openChange', open); this.$emit('openChange', open);
}, },
handleShowDateChange(showDate) { handleShowDateChange(showDate: boolean) {
this.setState({ sShowDate: showDate }); this.setState({ sShowDate: showDate });
}, },
handleHoverChange(hoverValue) { handleHoverChange(hoverValue: any) {
this.setState({ sHoverValue: hoverValue }); this.setState({ sHoverValue: hoverValue });
}, },
@ -180,7 +204,7 @@ export default {
} }
}, },
handleCalendarInputSelect(value) { handleCalendarInputSelect(value: RangePickerValue) {
const [start] = value; const [start] = value;
if (!start) { if (!start) {
return; return;
@ -191,7 +215,7 @@ export default {
})); }));
}, },
handleRangeClick(value) { handleRangeClick(value: RangePickerPresetRange) {
if (typeof value === 'function') { if (typeof value === 'function') {
value = value(); value = value();
} }
@ -201,10 +225,10 @@ export default {
this.$emit('openChange', false); this.$emit('openChange', false);
}, },
onMouseEnter(e) { onMouseEnter(e: MouseEvent) {
this.$emit('mouseenter', e); this.$emit('mouseenter', e);
}, },
onMouseLeave(e) { onMouseLeave(e: MouseEvent) {
this.$emit('mouseleave', e); this.$emit('mouseleave', e);
}, },
@ -218,7 +242,7 @@ export default {
renderFooter() { renderFooter() {
const { ranges, $slots } = this; const { ranges, $slots } = this;
const { _prefixCls: prefixCls, _tagPrefixCls: tagPrefixCls } = this; const { sPrefixCls: prefixCls, sTagPrefixCls: tagPrefixCls } = this;
const renderExtraFooter = this.renderExtraFooter || $slots.renderExtraFooter; const renderExtraFooter = this.renderExtraFooter || $slots.renderExtraFooter;
if (!ranges && !renderExtraFooter) { if (!ranges && !renderExtraFooter) {
return null; return null;
@ -257,7 +281,7 @@ export default {
}, },
render() { render() {
const props = { ...getOptionProps(this), ...this.$attrs }; const props: any = { ...getOptionProps(this), ...this.$attrs };
let suffixIcon = getComponent(this, 'suffixIcon'); let suffixIcon = getComponent(this, 'suffixIcon');
suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon; suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon;
const { const {
@ -291,8 +315,8 @@ export default {
const getPrefixCls = this.configProvider.getPrefixCls; const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('calendar', customizePrefixCls); const prefixCls = getPrefixCls('calendar', customizePrefixCls);
const tagPrefixCls = getPrefixCls('tag', customizeTagPrefixCls); const tagPrefixCls = getPrefixCls('tag', customizeTagPrefixCls);
this._prefixCls = prefixCls; this.sPrefixCls = prefixCls;
this._tagPrefixCls = tagPrefixCls; this.sTagPrefixCls = tagPrefixCls;
const dateRender = props.dateRender || $slots.dateRender; const dateRender = props.dateRender || $slots.dateRender;
fixLocale(value, localeCode); fixLocale(value, localeCode);
@ -307,7 +331,7 @@ export default {
const pickerChangeHandler = { const pickerChangeHandler = {
onChange: this.handleChange, onChange: this.handleChange,
}; };
let calendarProps = { let calendarProps: any = {
onOk: this.handleChange, onOk: this.handleChange,
}; };
if (props.timePicker) { if (props.timePicker) {
@ -353,7 +377,7 @@ export default {
const calendar = <RangeCalendar {...rangeCalendarProps} vSlots={$slots} />; const calendar = <RangeCalendar {...rangeCalendarProps} vSlots={$slots} />;
// default width for showTime // default width for showTime
const pickerStyle = {}; const pickerStyle: CSSProperties = {};
if (props.showTime) { if (props.showTime) {
pickerStyle.width = '350px'; pickerStyle.width = '350px';
} }
@ -407,8 +431,6 @@ export default {
id={props.id} id={props.id}
class={classNames(props.class, props.pickerClass)} class={classNames(props.class, props.pickerClass)}
style={{ ...style, ...pickerStyle }} style={{ ...style, ...pickerStyle }}
class={props.pickerClass}
style={pickerStyle}
tabindex={props.disabled ? -1 : 0} tabindex={props.disabled ? -1 : 0}
onFocus={onFocus} onFocus={onFocus}
onBlur={onBlur} onBlur={onBlur}
@ -420,4 +442,4 @@ export default {
</span> </span>
); );
}, },
}; });

View File

@ -1,37 +1,46 @@
import { inject } from 'vue'; import { defineComponent, inject } from 'vue';
import moment from 'moment'; import moment from 'moment';
import Calendar from '../vc-calendar'; import Calendar from '../vc-calendar';
import VcDatePicker from '../vc-calendar/src/Picker'; import VcDatePicker from '../vc-calendar/src/Picker';
import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled'; import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
import { defaultConfigProvider } from '../config-provider'; import { defaultConfigProvider } from '../config-provider';
import { hasProp, getOptionProps, initDefaultProps, getComponent } from '../_util/props-util'; import { hasProp, getOptionProps, getComponent } from '../_util/props-util';
import classNames from '../_util/classNames'; import classNames from '../_util/classNames';
import BaseMixin from '../_util/BaseMixin'; import BaseMixin from '../_util/BaseMixin';
import { WeekPickerProps } from './interface'; import { WeekPickerProps } from './interface';
import interopDefault from '../_util/interopDefault'; import interopDefault from '../_util/interopDefault';
import InputIcon from './InputIcon'; import InputIcon from './InputIcon';
import { getDataAndAriaProps } from '../_util/util'; import { getDataAndAriaProps } from '../_util/util';
import initDefaultProps from 'components/_util/props-util/initDefaultProps';
function formatValue(value, format) { function formatValue(value: moment.Moment | null, format: string): string {
return (value && value.format(format)) || ''; return (value && value.format(format)) || '';
} }
interface WeekPickerState {
_open?: boolean;
_value?: moment.Moment | null;
}
function noop() {} function noop() {}
export default { export default defineComponent({
name: 'AWeekPicker', name: 'AWeekPicker',
mixins: [BaseMixin], mixins: [BaseMixin],
inheritAttrs: false, inheritAttrs: false,
props: initDefaultProps(WeekPickerProps(), { props: initDefaultProps(WeekPickerProps, {
format: 'gggg-wo', format: 'gggg-wo',
allowClear: true, allowClear: true,
}), }),
setup() { setup() {
return { return {
configProvider: inject('configProvider', defaultConfigProvider), configProvider: inject('configProvider', defaultConfigProvider),
prevState: {} as WeekPickerState,
input: undefined,
sPrefixCls: undefined,
}; };
}, },
data() { data(): WeekPickerState {
const value = this.value || this.defaultValue; const value: any = this.value || this.defaultValue;
if (value && !interopDefault(moment).isMoment(value)) { if (value && !interopDefault(moment).isMoment(value)) {
throw new Error( throw new Error(
'The value/defaultValue of WeekPicker or MonthPicker must be ' + 'a moment object', 'The value/defaultValue of WeekPicker or MonthPicker must be ' + 'a moment object',
@ -72,12 +81,12 @@ export default {
}); });
}, },
methods: { methods: {
saveInput(node) { saveInput(node: any) {
this.input = node; this.input = node;
}, },
weekDateRender({ current }) { weekDateRender({ current }) {
const selectedValue = this.$data._value; const selectedValue = this.$data._value;
const { _prefixCls: prefixCls, $slots } = this; const { sPrefixCls: prefixCls, $slots } = this;
const dateRender = this.dateRender || $slots.dateRender; const dateRender = this.dateRender || $slots.dateRender;
const dateNode = dateRender ? dateRender({ current }) : current.date(); const dateNode = dateRender ? dateRender({ current }) : current.date();
if ( if (
@ -93,19 +102,19 @@ export default {
} }
return <div class={`${prefixCls}-date`}>{dateNode}</div>; return <div class={`${prefixCls}-date`}>{dateNode}</div>;
}, },
handleChange(value) { handleChange(value: moment.Moment | null) {
if (!hasProp(this, 'value')) { if (!hasProp(this, 'value')) {
this.setState({ _value: value }); this.setState({ _value: value });
} }
this.$emit('change', value, formatValue(value, this.format)); this.$emit('change', value, formatValue(value, this.format));
}, },
handleOpenChange(open) { handleOpenChange(open: boolean) {
if (!hasProp(this, 'open')) { if (!hasProp(this, 'open')) {
this.setState({ _open: open }); this.setState({ _open: open });
} }
this.$emit('openChange', open); this.$emit('openChange', open);
}, },
clearSelection(e) { clearSelection(e: MouseEvent) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
this.handleChange(null); this.handleChange(null);
@ -117,8 +126,8 @@ export default {
blur() { blur() {
this.input.blur(); this.input.blur();
}, },
renderFooter(...args) { renderFooter(...args: any[]) {
const { _prefixCls: prefixCls, $slots } = this; const { sPrefixCls: prefixCls, $slots } = this;
const renderExtraFooter = this.renderExtraFooter || $slots.renderExtraFooter; const renderExtraFooter = this.renderExtraFooter || $slots.renderExtraFooter;
return renderExtraFooter ? ( return renderExtraFooter ? (
<div class={`${prefixCls}-footer-extra`}>{renderExtraFooter(...args)}</div> <div class={`${prefixCls}-footer-extra`}>{renderExtraFooter(...args)}</div>
@ -147,10 +156,10 @@ export default {
} = this; } = this;
const getPrefixCls = this.configProvider.getPrefixCls; const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('calendar', customizePrefixCls); const prefixCls = getPrefixCls('calendar', customizePrefixCls);
this._prefixCls = prefixCls; this.sPrefixCls = prefixCls;
const { _value: pickerValue, _open: open } = $data; const { _value: pickerValue, _open: open } = $data;
const { class: className, style, id, onFocus = noop, onBlur = noop } = props; const { class: className, style, id, onFocus = noop, onBlur = noop } = props as any;
if (pickerValue && localeCode) { if (pickerValue && localeCode) {
pickerValue.locale(localeCode); pickerValue.locale(localeCode);
@ -169,7 +178,7 @@ export default {
showToday={false} showToday={false}
disabledDate={disabledDate} disabledDate={disabledDate}
renderFooter={this.renderFooter} renderFooter={this.renderFooter}
defaultValue={defaultPickerValue} defaultValue={defaultPickerValue as any}
/> />
); );
const clearIcon = const clearIcon =
@ -214,8 +223,8 @@ export default {
id={id} id={id}
{...getDataAndAriaProps(props)} {...getDataAndAriaProps(props)}
> >
<VcDatePicker {...vcDatePickerProps} vSlots={{ default: input, ...$slots }}></VcDatePicker> <VcDatePicker {...vcDatePickerProps} v-slots={{ default: input, ...$slots }}></VcDatePicker>
</span> </span>
); );
}, },
}; });

View File

@ -1,4 +1,4 @@
import { inject } from 'vue'; import { CSSProperties, DefineComponent, defineComponent, inject } from 'vue';
import moment from 'moment'; import moment from 'moment';
import omit from 'lodash-es/omit'; import omit from 'lodash-es/omit';
import MonthCalendar from '../vc-calendar/src/MonthCalendar'; import MonthCalendar from '../vc-calendar/src/MonthCalendar';
@ -9,66 +9,68 @@ import CalendarOutlined from '@ant-design/icons-vue/CalendarOutlined';
import { defaultConfigProvider } from '../config-provider'; import { defaultConfigProvider } from '../config-provider';
import interopDefault from '../_util/interopDefault'; import interopDefault from '../_util/interopDefault';
import BaseMixin from '../_util/BaseMixin'; import BaseMixin from '../_util/BaseMixin';
import { import PropTypes from '../_util/vue-types';
hasProp, import { hasProp, getOptionProps, getComponent, isValidElement } from '../_util/props-util';
getOptionProps,
initDefaultProps,
getComponent,
isValidElement,
} from '../_util/props-util';
import { cloneElement } from '../_util/vnode'; import { cloneElement } from '../_util/vnode';
import { formatDate } from './utils'; import { formatDate } from './utils';
import { getDataAndAriaProps } from '../_util/util'; import { getDataAndAriaProps } from '../_util/util';
// export const PickerProps = { export interface PickerProps {
// value?: moment.Moment; value?: moment.Moment;
// prefixCls: string; open?: boolean;
// } prefixCls?: string;
export default function createPicker(TheCalendar, props) { }
return { export interface PickerState {
sOpen?: boolean;
sValue?: moment.Moment | null;
showDate?: moment.Moment | null;
}
export default function createPicker(
TheCalendar: DefineComponent<any>,
props: any,
): DefineComponent<any> {
return defineComponent({
inheritAttrs: false, inheritAttrs: false,
props: initDefaultProps(props, { props: {
allowClear: true, ...props,
showToday: true, allowClear: PropTypes.looseBool.def(true),
}), showToday: PropTypes.looseBool.def(true),
},
mixins: [BaseMixin], mixins: [BaseMixin],
setup() { setup() {
return { return {
configProvider: inject('configProvider', defaultConfigProvider), configProvider: inject('configProvider', defaultConfigProvider),
input: undefined,
sPrefixCls: undefined,
}; };
}, },
data() { data(): PickerState {
const value = this.value || this.defaultValue; const value = this.value || this.defaultValue;
if (value && !interopDefault(moment).isMoment(value)) {
throw new Error(
'The value/defaultValue of DatePicker or MonthPicker must be ' + 'a moment object',
);
}
return { return {
sValue: value, sValue: value,
showDate: value, showDate: value,
_open: !!this.open, sOpen: !!this.open,
}; };
}, },
watch: { watch: {
open(val) { open(val) {
const props = getOptionProps(this); const props: PickerProps = getOptionProps(this);
const state = {}; const state: PickerState = {};
state._open = val; state.sOpen = val;
if ('value' in props && !val && props.value !== this.showDate) { if ('value' in props && !val && props.value !== this.showDate) {
state.showDate = props.value; state.showDate = props.value;
} }
this.setState(state); this.setState(state);
}, },
value(val) { value(val) {
const state = {}; const state: PickerState = {};
state.sValue = val; state.sValue = val;
if (val !== this.sValue) { if (val !== this.sValue) {
state.showDate = val; state.showDate = val;
} }
this.setState(state); this.setState(state);
}, },
_open(val, oldVal) { sOpen(val, oldVal) {
this.$nextTick(() => { this.$nextTick(() => {
if (!hasProp(this, 'open') && oldVal && !val) { if (!hasProp(this, 'open') && oldVal && !val) {
this.focus(); this.focus();
@ -77,16 +79,16 @@ export default function createPicker(TheCalendar, props) {
}, },
}, },
methods: { methods: {
saveInput(node) { saveInput(node: any) {
this.input = node; this.input = node;
}, },
clearSelection(e) { clearSelection(e: MouseEvent) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
this.handleChange(null); this.handleChange(null);
}, },
handleChange(value) { handleChange(value: moment.Moment | null) {
if (!hasProp(this, 'value')) { if (!hasProp(this, 'value')) {
this.setState({ this.setState({
sValue: value, sValue: value,
@ -96,13 +98,13 @@ export default function createPicker(TheCalendar, props) {
this.$emit('change', value, formatDate(value, this.format)); this.$emit('change', value, formatDate(value, this.format));
}, },
handleCalendarChange(value) { handleCalendarChange(value: moment.Moment) {
this.setState({ showDate: value }); this.setState({ showDate: value });
}, },
handleOpenChange(open) { handleOpenChange(open: boolean) {
const props = getOptionProps(this); const props = getOptionProps(this);
if (!('open' in props)) { if (!('open' in props)) {
this.setState({ _open: open }); this.setState({ sOpen: open });
} }
this.$emit('openChange', open); this.$emit('openChange', open);
}, },
@ -113,9 +115,9 @@ export default function createPicker(TheCalendar, props) {
blur() { blur() {
this.input?.blur(); this.input?.blur();
}, },
renderFooter(...args) { renderFooter(...args: any[]) {
const { $slots, _prefixCls: prefixCls } = this; const { $slots, sPrefixCls: prefixCls } = this;
const renderExtraFooter = this.renderExtraFooter || $slots.renderExtraFooter; const renderExtraFooter: Function = this.renderExtraFooter || $slots.renderExtraFooter;
return renderExtraFooter ? ( return renderExtraFooter ? (
<div class={`${prefixCls}-footer-extra`}> <div class={`${prefixCls}-footer-extra`}>
{typeof renderExtraFooter === 'function' {typeof renderExtraFooter === 'function'
@ -124,25 +126,25 @@ export default function createPicker(TheCalendar, props) {
</div> </div>
) : null; ) : null;
}, },
onMouseEnter(e) { onMouseEnter(e: MouseEvent) {
this.$emit('mouseenter', e); this.$emit('mouseenter', e);
}, },
onMouseLeave(e) { onMouseLeave(e: MouseEvent) {
this.$emit('mouseleave', e); this.$emit('mouseleave', e);
}, },
}, },
render() { render() {
const { $slots } = this; const { $slots } = this;
const { sValue: value, showDate, _open: open } = this.$data; const { sValue: value, showDate, sOpen: open } = this.$data;
let suffixIcon = getComponent(this, 'suffixIcon'); let suffixIcon = getComponent(this, 'suffixIcon');
suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon; suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon;
const props = omit({ ...getOptionProps(this), ...this.$attrs }, ['onChange']); const props: any = omit({ ...getOptionProps(this), ...this.$attrs }, ['onChange']);
const { prefixCls: customizePrefixCls, locale, localeCode, inputReadOnly } = props; const { prefixCls: customizePrefixCls, locale, localeCode, inputReadOnly } = props;
const getPrefixCls = this.configProvider.getPrefixCls; const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('calendar', customizePrefixCls); const prefixCls = getPrefixCls('calendar', customizePrefixCls);
this._prefixCls = prefixCls; this.sPrefixCls = prefixCls;
const dateRender = props.dateRender || $slots.dateRender; const dateRender = props.dateRender || $slots.dateRender;
const monthCellContentRender = props.monthCellContentRender || $slots.monthCellContentRender; const monthCellContentRender = props.monthCellContentRender || $slots.monthCellContentRender;
@ -152,16 +154,16 @@ export default function createPicker(TheCalendar, props) {
const calendarClassName = classNames({ const calendarClassName = classNames({
[`${prefixCls}-time`]: props.showTime, [`${prefixCls}-time`]: props.showTime,
[`${prefixCls}-month`]: MonthCalendar === TheCalendar, [`${prefixCls}-month`]: (MonthCalendar as any) === TheCalendar,
}); });
if (value && localeCode) { if (value && localeCode) {
value.locale(localeCode); value.locale(localeCode);
} }
const pickerProps = {}; const pickerProps: any = {};
const calendarProps = {}; const calendarProps: any = {};
const pickerStyle = {}; const pickerStyle: CSSProperties = {};
if (props.showTime) { if (props.showTime) {
// fix https://github.com/ant-design/ant-design/issues/1902 // fix https://github.com/ant-design/ant-design/issues/1902
calendarProps.onSelect = this.handleChange; calendarProps.onSelect = this.handleChange;
@ -251,10 +253,10 @@ export default function createPicker(TheCalendar, props) {
> >
<VcDatePicker <VcDatePicker
{...vcDatePickerProps} {...vcDatePickerProps}
vSlots={{ default: input, ...$slots }} v-slots={{ default: input, ...$slots }}
></VcDatePicker> ></VcDatePicker>
</span> </span>
); );
}, },
}; });
} }

View File

@ -5,27 +5,34 @@ import wrapPicker from './wrapPicker';
import RangePicker from './RangePicker'; import RangePicker from './RangePicker';
import WeekPicker from './WeekPicker'; import WeekPicker from './WeekPicker';
import { DatePickerProps, MonthPickerProps, WeekPickerProps, RangePickerProps } from './interface'; import { DatePickerProps, MonthPickerProps, WeekPickerProps, RangePickerProps } from './interface';
import { App, DefineComponent, defineComponent } from 'vue';
type DatePickerPropstypes = typeof DatePickerProps;
const DatePicker = wrapPicker( const DatePicker: DefineComponent<DatePickerPropstypes> = defineComponent<DatePickerPropstypes>(
{ ...createPicker(VcCalendar, DatePickerProps()), name: 'ADatePicker' }, wrapPicker(
DatePickerProps(), {
'date', ...createPicker(VcCalendar as any, DatePickerProps),
name: 'ADatePicker',
} as any,
DatePickerProps,
'date',
) as any,
); );
const MonthPicker = wrapPicker( const MonthPicker = wrapPicker(
{ ...createPicker(MonthCalendar, MonthPickerProps()), name: 'AMonthPicker' }, { ...createPicker(MonthCalendar as any, MonthPickerProps), name: 'AMonthPicker' } as any,
MonthPickerProps(), MonthPickerProps,
'month', 'month',
); );
Object.assign(DatePicker, { Object.assign(DatePicker, {
RangePicker: wrapPicker(RangePicker, RangePickerProps(), 'date'), RangePicker: wrapPicker(RangePicker as any, RangePickerProps, 'date'),
MonthPicker, MonthPicker,
WeekPicker: wrapPicker(WeekPicker, WeekPickerProps(), 'week'), WeekPicker: wrapPicker(WeekPicker as any, WeekPickerProps, 'week'),
}); });
/* istanbul ignore next */ /* istanbul ignore next */
DatePicker.install = function(app) { DatePicker.install = function(app: App) {
app.component(DatePicker.name, DatePicker); app.component(DatePicker.name, DatePicker);
app.component(DatePicker.RangePicker.name, DatePicker.RangePicker); app.component(DatePicker.RangePicker.name, DatePicker.RangePicker);
app.component(DatePicker.MonthPicker.name, DatePicker.MonthPicker); app.component(DatePicker.MonthPicker.name, DatePicker.MonthPicker);

View File

@ -1,8 +1,19 @@
// import { TimePickerProps } from '../time-picker' // import { TimePickerProps } from '../time-picker'
import PropTypes, { withUndefined } from '../_util/vue-types'; import PropTypes, { withUndefined } from '../_util/vue-types';
import { TimesType, TimeType } from '../_util/moment-util'; import { tuple } from 'components/_util/type';
import { PropType } from 'vue';
export const PickerProps = () => ({ export type PickerValue = moment.Moment | undefined | null | string;
export type RangePickerValue =
| undefined[]
| null[]
| [moment.Moment | string]
| [undefined, moment.Moment | string]
| [moment.Moment | string, undefined]
| [null, moment.Moment | string]
| [moment.Moment | string, null]
| [moment.Moment, moment.Moment]
| [string, string];
export const PickerProps = {
name: PropTypes.string, name: PropTypes.string,
transitionName: PropTypes.string, transitionName: PropTypes.string,
prefixCls: PropTypes.string, prefixCls: PropTypes.string,
@ -15,7 +26,7 @@ export const PickerProps = () => ({
dropdownClassName: PropTypes.string, dropdownClassName: PropTypes.string,
locale: PropTypes.any, locale: PropTypes.any,
localeCode: PropTypes.string, localeCode: PropTypes.string,
size: PropTypes.oneOf(['large', 'small', 'default']), size: PropTypes.oneOf(tuple('large', 'small', 'default')),
getCalendarContainer: PropTypes.func, getCalendarContainer: PropTypes.func,
open: PropTypes.looseBool, open: PropTypes.looseBool,
disabledDate: PropTypes.func, disabledDate: PropTypes.func,
@ -36,43 +47,43 @@ export const PickerProps = () => ({
'onUpdate:value': PropTypes.func, 'onUpdate:value': PropTypes.func,
onMouseenter: PropTypes.func, onMouseenter: PropTypes.func,
onMouseleave: PropTypes.func, onMouseleave: PropTypes.func,
}); };
export const SinglePickerProps = () => ({ export const SinglePickerProps = {
value: TimeType, value: { type: [String, Object] as PropType<PickerValue> },
defaultValue: TimeType, defaultValue: { type: [String, Object] as PropType<PickerValue> },
defaultPickerValue: TimeType, defaultPickerValue: { type: [String, Object] as PropType<PickerValue> },
renderExtraFooter: PropTypes.any, renderExtraFooter: PropTypes.any,
placeholder: PropTypes.string, placeholder: PropTypes.string,
onChange: PropTypes.func, onChange: PropTypes.func,
}); };
export const DatePickerProps = () => ({ export const DatePickerProps = {
...PickerProps(), ...PickerProps,
...SinglePickerProps(), ...SinglePickerProps,
showTime: withUndefined(PropTypes.oneOfType([PropTypes.object, PropTypes.looseBool])), showTime: withUndefined(PropTypes.oneOfType([PropTypes.object, PropTypes.looseBool])),
open: PropTypes.looseBool, open: PropTypes.looseBool,
disabledTime: PropTypes.func, disabledTime: PropTypes.func,
mode: PropTypes.oneOf(['time', 'date', 'month', 'year']), mode: PropTypes.oneOf(tuple('time', 'date', 'month', 'year')),
onOpenChange: PropTypes.func, onOpenChange: PropTypes.func,
onPanelChange: PropTypes.func, onPanelChange: PropTypes.func,
onOk: PropTypes.func, onOk: PropTypes.func,
}); };
export const MonthPickerProps = () => ({ export const MonthPickerProps = {
...PickerProps(), ...PickerProps,
...SinglePickerProps(), ...SinglePickerProps,
placeholder: PropTypes.string, placeholder: PropTypes.string,
monthCellContentRender: PropTypes.func, monthCellContentRender: PropTypes.func,
}); };
// export const RangePickerPresetRange = PropTypes.oneOfType([TimesType, PropTypes.func]) // export const RangePickerPresetRange = PropTypes.oneOfType([TimesType, PropTypes.func])
export const RangePickerProps = () => ({ export const RangePickerProps = {
...PickerProps(), ...PickerProps,
tagPrefixCls: PropTypes.string, tagPrefixCls: PropTypes.string,
value: TimesType, value: { type: Array as PropType<RangePickerValue> },
defaultValue: TimesType, defaultValue: { type: Array as PropType<RangePickerValue> },
defaultPickerValue: TimesType, defaultPickerValue: { type: Array as PropType<RangePickerValue> },
timePicker: PropTypes.any, timePicker: PropTypes.any,
showTime: withUndefined(PropTypes.oneOfType([PropTypes.object, PropTypes.looseBool])), showTime: withUndefined(PropTypes.oneOfType([PropTypes.object, PropTypes.looseBool])),
ranges: PropTypes.object, ranges: PropTypes.object,
@ -88,13 +99,13 @@ export const RangePickerProps = () => ({
onPanelChange: PropTypes.func, onPanelChange: PropTypes.func,
onMouseenter: PropTypes.func, onMouseenter: PropTypes.func,
onMouseleave: PropTypes.func, onMouseleave: PropTypes.func,
}); };
export const WeekPickerProps = () => ({ export const WeekPickerProps = {
...PickerProps(), ...PickerProps,
...SinglePickerProps(), ...SinglePickerProps,
placeholder: PropTypes.string, placeholder: PropTypes.string,
}); };
// export interface DatePickerDecorator extends React.ClassicComponentClass<DatePickerProps> { // export interface DatePickerDecorator extends React.ClassicComponentClass<DatePickerProps> {
// RangePicker: React.ClassicComponentClass<RangePickerProps>; // RangePicker: React.ClassicComponentClass<RangePickerProps>;

View File

@ -1,17 +0,0 @@
export function formatDate(value, format) {
if (!value) {
return '';
}
if (Array.isArray(format)) {
format = format[0];
}
if (typeof format === 'function') {
const result = format(value);
if (typeof result === 'string') {
return result;
} else {
throw new Error('The function of format does not return a string');
}
}
return value.format(format);
}

View File

@ -0,0 +1,14 @@
type Value = moment.Moment | undefined | null;
type Format = string | string[] | undefined | ((val?: Value) => string | string[] | undefined);
export function formatDate(value: Value, format: Format) {
if (!value) {
return '';
}
if (Array.isArray(format)) {
format = format[0];
}
if (typeof format === 'function') {
return format(value);
}
return value.format(format);
}

View File

@ -1,28 +1,34 @@
import { provide, inject } from 'vue'; import { provide, inject, defineComponent, DefineComponent } from 'vue';
import TimePickerPanel from '../vc-time-picker/Panel'; import TimePickerPanel from '../vc-time-picker/Panel';
import classNames from '../_util/classNames'; import classNames from '../_util/classNames';
import LocaleReceiver from '../locale-provider/LocaleReceiver'; import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { generateShowHourMinuteSecond } from '../time-picker'; import { generateShowHourMinuteSecond } from '../time-picker';
import enUS from './locale/en_US'; import enUS from './locale/en_US';
import { getOptionProps, initDefaultProps } from '../_util/props-util'; import PropTypes from '../_util/vue-types';
import { getOptionProps } from '../_util/props-util';
import { defaultConfigProvider } from '../config-provider'; import { defaultConfigProvider } from '../config-provider';
import { checkValidate, stringToMoment, momentToString } from '../_util/moment-util'; import { checkValidate, stringToMoment, momentToString } from '../_util/moment-util';
const DEFAULT_FORMAT = { type PickerType = 'date' | 'week' | 'month';
interface PickerMap {
[name: string]: string;
}
const DEFAULT_FORMAT: PickerMap = {
date: 'YYYY-MM-DD', date: 'YYYY-MM-DD',
dateTime: 'YYYY-MM-DD HH:mm:ss', dateTime: 'YYYY-MM-DD HH:mm:ss',
week: 'gggg-wo', week: 'gggg-wo',
month: 'YYYY-MM', month: 'YYYY-MM',
}; };
const LOCALE_FORMAT_MAPPING = { const LOCALE_FORMAT_MAPPING: PickerMap = {
date: 'dateFormat', date: 'dateFormat',
dateTime: 'dateTimeFormat', dateTime: 'dateTimeFormat',
week: 'weekFormat', week: 'weekFormat',
month: 'monthFormat', month: 'monthFormat',
}; };
function getColumns({ showHour, showMinute, showSecond, use12Hours }) { function getColumns({ showHour, showMinute, showSecond, use12Hours }: any) {
let column = 0; let column = 0;
if (showHour) { if (showHour) {
column += 1; column += 1;
@ -38,23 +44,25 @@ function getColumns({ showHour, showMinute, showSecond, use12Hours }) {
} }
return column; return column;
} }
export default function wrapPicker(
export default function wrapPicker(Picker, props, pickerType) { Picker: DefineComponent<any>,
return { props: any,
pickerType: PickerType,
) {
return defineComponent({
name: Picker.name, name: Picker.name,
inheritAttrs: false, inheritAttrs: false,
props: initDefaultProps(props, { props: {
transitionName: 'slide-up', ...props,
popupStyle: {}, transitionName: PropTypes.string.def('slide-up'),
locale: {}, popupStyle: PropTypes.style,
}), locale: PropTypes.any.def({}),
// model: { },
// prop: 'value',
// event: 'change',
// },
setup() { setup() {
return { return {
configProvider: inject('configProvider', defaultConfigProvider), configProvider: inject('configProvider', defaultConfigProvider),
picker: undefined,
popupRef: undefined,
}; };
}, },
created() { created() {
@ -76,7 +84,7 @@ export default function wrapPicker(Picker, props, pickerType) {
}, },
}, },
methods: { methods: {
savePicker(node) { savePicker(node: any) {
this.picker = node; this.picker = node;
}, },
getDefaultLocale() { getDefaultLocale() {
@ -91,37 +99,37 @@ export default function wrapPicker(Picker, props, pickerType) {
return result; return result;
}, },
savePopupRef(ref) { savePopupRef(ref: any) {
this.popupRef = ref; this.popupRef = ref;
}, },
handleOpenChange(open) { handleOpenChange(open: boolean) {
this.$emit('openChange', open); this.$emit('openChange', open);
}, },
handleFocus(e) { handleFocus(e: FocusEvent) {
this.$emit('focus', e); this.$emit('focus', e);
}, },
handleBlur(e) { handleBlur(e: FocusEvent) {
this.$emit('blur', e); this.$emit('blur', e);
}, },
handleMouseEnter(e) { handleMouseEnter(e: MouseEvent) {
this.$emit('mouseenter', e); this.$emit('mouseenter', e);
}, },
handleMouseLeave(e) { handleMouseLeave(e: MouseEvent) {
this.$emit('mouseleave', e); this.$emit('mouseleave', e);
}, },
handleChange(date, dateString) { handleChange(date: any, dateString: string) {
const value = this.valueFormat ? momentToString(date, this.valueFormat) : date; const value = this.valueFormat ? momentToString(date, this.valueFormat) : date;
this.$emit('update:value', value); this.$emit('update:value', value);
this.$emit('change', value, dateString); this.$emit('change', value, dateString);
}, },
handleOk(val) { handleOk(val: any) {
this.$emit('ok', this.valueFormat ? momentToString(val, this.valueFormat) : val); this.$emit('ok', this.valueFormat ? momentToString(val, this.valueFormat) : val);
}, },
handleCalendarChange(date, dateString) { handleCalendarChange(date: any, dateString: string) {
this.$emit( this.$emit(
'calendarChange', 'calendarChange',
this.valueFormat ? momentToString(date, this.valueFormat) : date, this.valueFormat ? momentToString(date, this.valueFormat) : date,
@ -148,8 +156,8 @@ export default function wrapPicker(Picker, props, pickerType) {
} }
}, },
renderPicker(locale, localeCode) { renderPicker(locale: any, localeCode: string) {
const props = { ...getOptionProps(this), ...this.$attrs }; const props: any = { ...getOptionProps(this), ...this.$attrs };
this.transformValue(props); this.transformValue(props);
const { const {
prefixCls: customizePrefixCls, prefixCls: customizePrefixCls,
@ -230,5 +238,5 @@ export default function wrapPicker(Picker, props, pickerType) {
/> />
); );
}, },
}; });
} }

View File

@ -5,6 +5,7 @@ import BaseMixin from '../_util/BaseMixin';
import Header from './Header'; import Header from './Header';
import Combobox from './Combobox'; import Combobox from './Combobox';
import { getComponent } from '../_util/props-util'; import { getComponent } from '../_util/props-util';
import { defineComponent } from 'vue';
function noop() {} function noop() {}
@ -31,7 +32,7 @@ function toNearestValidTime(time, hourOptions, minuteOptions, secondOptions) {
return moment(`${hour}:${minute}:${second}`, 'HH:mm:ss'); return moment(`${hour}:${minute}:${second}`, 'HH:mm:ss');
} }
const Panel = { const Panel = defineComponent({
name: 'Panel', name: 'Panel',
inheritAttrs: false, inheritAttrs: false,
mixins: [BaseMixin], mixins: [BaseMixin],
@ -223,6 +224,6 @@ const Panel = {
</div> </div>
); );
}, },
}; });
export default Panel; export default Panel;

View File

@ -1,4 +1,4 @@
import Empty from '../components/empty'; import Empty from '../components/date-picker';
import '../components/empty/style'; import '../components/empty/style';
export default { export default {