From 300fc9a2bc9579b840f0d4ce5068e3beab390992 Mon Sep 17 00:00:00 2001 From: wangxueliang Date: Sat, 20 Apr 2019 12:34:24 +0800 Subject: [PATCH] feat: update date-picker --- components/date-picker/RangePicker.jsx | 39 ++++++++++++----- components/date-picker/WeekPicker.jsx | 51 +++++++++++++++++----- components/date-picker/createPicker.js | 37 ++++++++++------ components/date-picker/demo/mode.md | 5 ++- components/date-picker/demo/time.md | 1 - components/date-picker/index.en-US.md | 8 ++-- components/date-picker/index.js | 7 +-- components/date-picker/index.zh-CN.md | 8 ++-- components/date-picker/interface.js | 1 + components/date-picker/locale/example.json | 6 +-- components/date-picker/wrapPicker.js | 44 ++++++++++++++++--- components/modal/demo/confirm-router.md | 2 +- 12 files changed, 150 insertions(+), 59 deletions(-) diff --git a/components/date-picker/RangePicker.jsx b/components/date-picker/RangePicker.jsx index f9665d00f..3af35c668 100644 --- a/components/date-picker/RangePicker.jsx +++ b/components/date-picker/RangePicker.jsx @@ -5,6 +5,7 @@ import classNames from 'classnames'; import shallowequal from 'shallowequal'; import Icon from '../icon'; import Tag from '../tag'; +import { ConfigConsumerProps } from '../config-provider'; import interopDefault from '../_util/interopDefault'; import { RangePickerProps } from './interface'; import { @@ -73,11 +74,12 @@ export default { event: 'change', }, props: initDefaultProps(RangePickerProps(), { - prefixCls: 'ant-calendar', - tagPrefixCls: 'ant-tag', allowClear: true, showToday: false, }), + inject: { + configProvider: { default: () => ({}) }, + }, data() { const value = this.value || this.defaultValue || []; const [start, end] = value; @@ -109,13 +111,24 @@ export default { }; } this.setState(state); + this.prevState = {...this.$data, ...state}; }, open(val) { - this.setState({ - sOpen: val, - }); + const state = { sOpen: val}; + this.setState(state); + this.prevState = {...this.$data, ...state}; }, }, + mounted() { + this.prevState = {...this.$data}; + }, + updated() { + this.$nextTick(() => { + if(!hasProp(this, 'open') && this.prevState.sOpen && !this.sOpen) { + this.focus(); + } + }); + }, methods: { clearSelection(e) { e.preventDefault(); @@ -148,10 +161,6 @@ export default { this.clearHoverValue(); } this.$emit('openChange', open); - - if (!open) { - this.focus(); - } }, handleShowDateChange(showDate) { @@ -212,7 +221,8 @@ export default { }, renderFooter(...args) { - const { prefixCls, ranges, $scopedSlots, $slots, tagPrefixCls } = this; + const { ranges, $scopedSlots, $slots } = this; + const { _prefixCls: prefixCls, _tagPrefixCls: tagPrefixCls } = this; const renderExtraFooter = this.renderExtraFooter || $scopedSlots.renderExtraFooter || $slots.renderExtraFooter; if (!ranges && !renderExtraFooter) { @@ -268,7 +278,8 @@ export default { panelChange = noop, } = $listeners; const { - prefixCls, + prefixCls: customizePrefixCls, + tagPrefixCls: customizeTagPrefixCls, popupStyle, disabledDate, disabledTime, @@ -279,6 +290,12 @@ export default { localeCode, format, } = props; + const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls; + const prefixCls = getPrefixCls('calendar', customizePrefixCls); + const tagPrefixCls = getPrefixCls('tag', customizeTagPrefixCls); + this._prefixCls = prefixCls; + this._tagPrefixCls = tagPrefixCls; + const dateRender = props.dateRender || $scopedSlots.dateRender; fixLocale(value, localeCode); fixLocale(showDate, localeCode); diff --git a/components/date-picker/WeekPicker.jsx b/components/date-picker/WeekPicker.jsx index 912efbd9a..72180b550 100644 --- a/components/date-picker/WeekPicker.jsx +++ b/components/date-picker/WeekPicker.jsx @@ -2,6 +2,7 @@ import * as moment from 'moment'; import Calendar from '../vc-calendar'; import VcDatePicker from '../vc-calendar/src/Picker'; import Icon from '../icon'; +import { ConfigConsumerProps } from '../config-provider'; import { hasProp, getOptionProps, @@ -36,6 +37,9 @@ export default { format: 'gggg-wo', allowClear: true, }), + inject: { + configProvider: { default: () => ({}) }, + }, data() { const value = this.value || this.defaultValue; if (value && !interopDefault(moment).isMoment(value)) { @@ -50,17 +54,32 @@ export default { }, watch: { value(val) { - this.setState({ _value: val }); + const state = { _value: val }; + this.setState(state); + this.prevState = {...this.$data, ...state}; }, open(val) { - this.setState({ _open: val }); + const state = { _open: val }; + this.setState(state); + this.prevState = {...this.$data, ...state}; }, }, - + mounted() { + this.prevState = {...this.$data}; + }, + updated() { + this.$nextTick(() => { + if(!hasProp(this, 'open') && this.prevState._open && !this._open) { + this.focus(); + } + }); + }, methods: { weekDateRender(current) { const selectedValue = this.$data._value; - const { prefixCls } = this; + const { _prefixCls: prefixCls, $scopedSlots } = this; + const dateRender = this.dateRender || $scopedSlots.dateRender; + const dateNode = dateRender ? dateRender(current) : current.date(); if ( selectedValue && current.year() === selectedValue.year() && @@ -68,11 +87,11 @@ export default { ) { return (
-
{current.date()}
+
{dateNode}
); } - return
{current.date()}
; + return
{dateNode}
; }, handleChange(value) { if (!hasProp(this, 'value')) { @@ -85,17 +104,19 @@ export default { this.setState({ _open: open }); } this.$emit('openChange', open); - - if (!open) { - this.focus(); - } }, clearSelection(e) { e.preventDefault(); e.stopPropagation(); this.handleChange(null); }, - + renderFooter(...args) { + const {_prefixCls: prefixCls, $scopedSlots} = this; + const renderExtraFooter = this.renderExtraFooter || $scopedSlots.renderExtraFooter; + return renderExtraFooter ? ( + + ) : null; + }, focus() { this.$refs.input.focus(); }, @@ -110,7 +131,7 @@ export default { let suffixIcon = getComponentFromProp(this, 'suffixIcon'); suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon; const { - prefixCls, + prefixCls: customizePrefixCls, disabled, pickerClass, popupStyle, @@ -124,6 +145,11 @@ export default { $listeners, $scopedSlots, } = this; + + const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls; + const prefixCls = getPrefixCls('calendar', customizePrefixCls); + this._prefixCls = prefixCls; + const { _value: pickerValue, _open: open } = $data; const { focus = noop, blur = noop } = $listeners; @@ -143,6 +169,7 @@ export default { showDateInput={false} showToday={false} disabledDate={disabledDate} + renderFooter={this.renderFooter} /> ); const clearIcon = diff --git a/components/date-picker/createPicker.js b/components/date-picker/createPicker.js index 14915e828..4338524da 100644 --- a/components/date-picker/createPicker.js +++ b/components/date-picker/createPicker.js @@ -4,6 +4,7 @@ import MonthCalendar from '../vc-calendar/src/MonthCalendar'; import VcDatePicker from '../vc-calendar/src/Picker'; import classNames from 'classnames'; import Icon from '../icon'; +import { ConfigConsumerProps } from '../config-provider'; import interopDefault from '../_util/interopDefault'; import BaseMixin from '../_util/BaseMixin'; import { @@ -23,15 +24,7 @@ import { cloneElement } from '../_util/vnode'; function noop() {} export default function createPicker(TheCalendar, props) { return { - // static defaultProps = { - // prefixCls: 'ant-calendar', - // allowClear: true, - // showToday: true, - // }; - - // private input: any; props: initDefaultProps(props, { - prefixCls: 'ant-calendar', allowClear: true, showToday: true, }), @@ -40,6 +33,9 @@ export default function createPicker(TheCalendar, props) { prop: 'value', event: 'change', }, + inject: { + configProvider: { default: () => ({}) }, + }, data() { const value = this.value || this.defaultValue; if (value && !interopDefault(moment).isMoment(value)) { @@ -62,6 +58,7 @@ export default function createPicker(TheCalendar, props) { state.showDate = props.value; } this.setState(state); + this.prevState = {...this.$data, ...state}; }, value(val) { const state = {}; @@ -70,11 +67,23 @@ export default function createPicker(TheCalendar, props) { state.showDate = val; } this.setState(state); + this.prevState = {...this.$data, ...state}; }, }, + mounted() { + this.prevState = {...this.$data}; + }, + updated() { + this.$nextTick(() => { + if(!hasProp(this, 'open') && this.prevState._open && !this._open) { + this.focus(); + } + }); + }, methods: { renderFooter(...args) { - const { prefixCls, $scopedSlots, $slots } = this; + const { $scopedSlots, $slots } = this; + const { _prefixCls: prefixCls } = this; const renderExtraFooter = this.renderExtraFooter || $scopedSlots.renderExtraFooter || $slots.renderExtraFooter; return renderExtraFooter ? ( @@ -111,9 +120,6 @@ export default function createPicker(TheCalendar, props) { this.setState({ _open: open }); } this.$emit('openChange', open); - if (!open) { - this.focus(); - } }, focus() { this.$refs.input.focus(); @@ -137,7 +143,12 @@ export default function createPicker(TheCalendar, props) { suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon; const { panelChange = noop, focus = noop, blur = noop, ok = noop } = $listeners; const props = getOptionProps(this); - const { prefixCls, locale, localeCode } = props; + + const { prefixCls: customizePrefixCls, locale, localeCode } = props; + const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls; + const prefixCls = getPrefixCls('calendar', customizePrefixCls); + this._prefixCls = prefixCls; + const dateRender = props.dateRender || $scopedSlots.dateRender; const monthCellContentRender = props.monthCellContentRender || $scopedSlots.monthCellContentRender; diff --git a/components/date-picker/demo/mode.md b/components/date-picker/demo/mode.md index 23016b38e..48ccb3773 100644 --- a/components/date-picker/demo/mode.md +++ b/components/date-picker/demo/mode.md @@ -25,6 +25,7 @@ Determing which panel to show with `mode` and `onPanelChange`. :value="value" :mode="mode2" @panelChange="handlePanelChange2" + @change="handleChange" /> @@ -43,7 +44,9 @@ export default { this.mode1 = 'time' } }, - + handleChange(value){ + this.value = value + }, handlePanelChange1(value, mode) { this.mode1 = mode }, diff --git a/components/date-picker/demo/time.md b/components/date-picker/demo/time.md index 95ba85529..71eee2fc6 100644 --- a/components/date-picker/demo/time.md +++ b/components/date-picker/demo/time.md @@ -14,7 +14,6 @@ This property provide an additional time selection. When `showTime` is an Object
boolean | - | | getCalendarContainer | to set the container of the floating layer, while the default is to create a `div` element in `body` | function(trigger) | - | | locale | localization configuration | object | [default](https://github.com/vueComponent/ant-design-vue/blob/master/components/date-picker/locale/example.json) | +| mode | picker panel mode | `time|date|month|year` | 'date' | | open | open state of picker | boolean | - | | placeholder | placeholder of date input | string\|RangePicker\[] | - | | popupStyle | to customize the style of the popup calendar | object | {} | @@ -61,7 +62,7 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke | defaultPickerValue | to set default picker date | [moment](http://momentjs.com/) | - | | disabledTime | to specify the time that cannot be selected | function(date) | - | | format | to set the date format, refer to [moment.js](http://momentjs.com/) | string | "YYYY-MM-DD" | -| renderExtraFooter | render extra footer in panel by setting a scoped slot | slot="renderExtraFooter" | - | +| renderExtraFooter | render extra footer in panel by setting a scoped slot | slot="renderExtraFooter" slot-scope="mode" | - | | showTime | to provide an additional time selection | object\|boolean | [TimePicker Options](/components/time-picker/#API) | | showTime.defaultValue | to set default time of selected date | [moment](http://momentjs.com/) | moment() | | showToday | whether to show "Today" button | boolean | true | @@ -82,7 +83,7 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke | defaultPickerValue | to set default picker date | [moment](http://momentjs.com/) | - | | format | 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](http://momentjs.com/) | string \| string[] | "YYYY-MM" | | monthCellContentRender | Custom month cell content render method by setting a scoped slot | slot="monthCellContentRender" slot-scope="date, locale" | - | -| renderExtraFooter | render extra footer in panel by setting a scoped slot | slot="renderExtraFooter" | - | +| renderExtraFooter | render extra footer in panel by setting a scoped slot | slot="renderExtraFooter" slot-scope="mode" | - | | value(v-model) | to set date | [moment](http://momentjs.com/) | - | ### MonthPicker Events @@ -98,6 +99,7 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke | defaultPickerValue | to set default picker date | [moment](http://momentjs.com/) | - | | format | to set the date format, refer to [moment.js](http://momentjs.com/) | string | "YYYY-wo" | | value(v-model) | to set date | [moment](http://momentjs.com/) | - | +| renderExtraFooter | render extra footer in panel by setting a scoped slot | slot="renderExtraFooter" slot-scope="mode" | - | ### WeekPicker Events | Events Name | Description | Arguments | @@ -113,7 +115,7 @@ The following APIs are shared by DatePicker, MonthPicker, RangePicker, WeekPicke | disabledTime | to specify the time that cannot be selected | function(dates: \[moment, moment\], partial: `'start'|'end'`) | - | | format | to set the date format | string | "YYYY-MM-DD HH:mm:ss" | | ranges | preseted ranges for quick selection | { \[range: string]: [moment](http://momentjs.com/)\[] } \| { \[range: string]: () => [moment](http://momentjs.com/)\[] } | - | -| renderExtraFooter | render extra footer in panel by setting a scoped slot| slot="renderExtraFooter" | - | +| renderExtraFooter | render extra footer in panel by setting a scoped slot| slot="renderExtraFooter" slot-scope="mode" | - | | showTime | to provide an additional time selection | object\|boolean | [TimePicker Options](/components/time-picker/#API) | | showTime.defaultValue | to set default time of selected date, [demo](https://ant.design/components/date-picker/#components-date-picker-demo-disabled-date) | [moment](http://momentjs.com/)\[] | \[moment(), moment()] | | value(v-model) | to set date | \[[moment](http://momentjs.com/), [moment](http://momentjs.com/)] | - | diff --git a/components/date-picker/index.js b/components/date-picker/index.js index 297449089..3e4b1de59 100755 --- a/components/date-picker/index.js +++ b/components/date-picker/index.js @@ -9,18 +9,19 @@ import { DatePickerProps, MonthPickerProps, WeekPickerProps, RangePickerProps } const DatePicker = wrapPicker( { ...createPicker(VcCalendar, DatePickerProps()), name: 'ADatePicker' }, DatePickerProps(), + 'date' ); const MonthPicker = wrapPicker( { ...createPicker(MonthCalendar, MonthPickerProps()), name: 'AMonthPicker' }, MonthPickerProps(), - 'YYYY-MM', + 'month', ); Object.assign(DatePicker, { - RangePicker: wrapPicker(RangePicker, RangePickerProps()), + RangePicker: wrapPicker(RangePicker, RangePickerProps(), 'date'), MonthPicker, - WeekPicker: wrapPicker(WeekPicker, WeekPickerProps(), 'gggg-wo'), + WeekPicker: wrapPicker(WeekPicker, WeekPickerProps(), 'week'), }); /* istanbul ignore next */ diff --git a/components/date-picker/index.zh-CN.md b/components/date-picker/index.zh-CN.md index ea2bbcaa1..487f09c6b 100644 --- a/components/date-picker/index.zh-CN.md +++ b/components/date-picker/index.zh-CN.md @@ -61,7 +61,8 @@ moment.locale('zh-cn'); | defaultPickerValue | 默认面板日期 | [moment](http://momentjs.com/) | 无 | | disabledTime | 不可选择的时间 | function(date) | 无 | | format | 设置日期格式,为数组时支持多格式匹配,展示以第一个为准。配置参考 [moment.js](http://momentjs.com/) | string \| string[] | "YYYY-MM-DD" | -| renderExtraFooter | 在面板中添加额外的页脚 | slot="renderExtraFooter" | - | +| mode | 日期面板的状态 | `time|date|month|year` | 'date' | +| renderExtraFooter | 在面板中添加额外的页脚 | slot="renderExtraFooter" slot-scope="mode" | - | | showTime | 增加时间选择功能 | Object\|boolean | [TimePicker Options](/components/time-picker-cn/#API) | | showTime.defaultValue | 设置用户选择日期时默认的时分秒 | [moment](http://momentjs.com/) | moment() | | showToday | 是否展示“今天”按钮 | boolean | true | @@ -82,7 +83,7 @@ moment.locale('zh-cn'); | defaultPickerValue | 默认面板日期 | [moment](http://momentjs.com/) | 无 | | format | 展示的日期格式,配置参考 [moment.js](http://momentjs.com/) | string | "YYYY-MM" | | monthCellContentRender | 自定义的月份内容渲染方法 | slot="monthCellContentRender" slot-scope="date, locale" | - | -| renderExtraFooter | 在面板中添加额外的页脚 | slot="renderExtraFooter" | - | +| renderExtraFooter | 在面板中添加额外的页脚 | slot="renderExtraFooter" slot-scope="mode" | - | | value(v-model) | 日期 | [moment](http://momentjs.com/) | 无 | ### MonthPicker事件 @@ -99,6 +100,7 @@ moment.locale('zh-cn'); | defaultPickerValue | 默认面板日期 | [moment](http://momentjs.com/) | 无 | | format | 展示的日期格式,配置参考 [moment.js](http://momentjs.com/) | string | "YYYY-wo" | | value(v-model) | 日期 | [moment](http://momentjs.com/) | - | +| renderExtraFooter | 在面板中添加额外的页脚 | slot="renderExtraFooter" slot-scope="mode" | - | ### WeekPicker事件 @@ -115,7 +117,7 @@ moment.locale('zh-cn'); | disabledTime | 不可选择的时间 | function(dates: \[moment, moment\], partial: `'start'|'end'`) | 无 | | format | 展示的日期格式 | string | "YYYY-MM-DD HH:mm:ss" | | ranges       | 预设时间范围快捷选择 | { \[range: string]: [moment](http://momentjs.com/)\[] } \| { \[range: string]: () => [moment](http://momentjs.com/)\[] } | 无 | -| renderExtraFooter | 在面板中添加额外的页脚 | slot="renderExtraFooter" | - | +| renderExtraFooter | 在面板中添加额外的页脚 | slot="renderExtraFooter" slot-scope="mode" | - | | showTime | 增加时间选择功能 | Object\|boolean | [TimePicker Options](/components/time-picker-cn/#API) | | showTime.defaultValue | 设置用户选择日期时默认的时分秒 | [moment](http://momentjs.com/)\[] | \[moment(), moment()] | | value(v-model) | 日期 | [moment](http://momentjs.com/)\[] | 无 | diff --git a/components/date-picker/interface.js b/components/date-picker/interface.js index 8b64cf74d..0b53f25f3 100644 --- a/components/date-picker/interface.js +++ b/components/date-picker/interface.js @@ -53,6 +53,7 @@ export const DatePickerProps = () => ({ // onOpenChange?: (status: bool) => void; // onOk?: (selectedTime: moment.Moment) => void; placeholder: PropTypes.string, + mode: PropTypes.oneOf(['time', 'date', 'month', 'year']), }); export const MonthPickerProps = () => ({ diff --git a/components/date-picker/locale/example.json b/components/date-picker/locale/example.json index 4c260f922..b7b0aa3a7 100644 --- a/components/date-picker/locale/example.json +++ b/components/date-picker/locale/example.json @@ -31,9 +31,5 @@ }, "timePickerLocale": { "placeholder": "Select time" - }, - "dateFormat": "YYYY-MM-DD", - "dateTimeFormat": "YYYY-MM-DD HH:mm:ss", - "weekFormat": "YYYY-wo", - "monthFormat": "YYYY-MM" + } } diff --git a/components/date-picker/wrapPicker.js b/components/date-picker/wrapPicker.js index dd47d7e69..c1d2d3bc4 100644 --- a/components/date-picker/wrapPicker.js +++ b/components/date-picker/wrapPicker.js @@ -4,6 +4,21 @@ import LocaleReceiver from '../locale-provider/LocaleReceiver'; import { generateShowHourMinuteSecond } from '../time-picker'; import enUS from './locale/en_US'; import { getOptionProps, initDefaultProps } from '../_util/props-util'; +import { ConfigConsumerProps } from '../config-provider'; + +const DEFAULT_FORMAT = { + date: 'YYYY-MM-DD', + dateTime: 'YYYY-MM-DD HH:mm:ss', + week: 'gggg-wo', + month: 'YYYY-MM', +}; + +const LOCALE_FORMAT_MAPPING = { + date: 'dateFormat', + dateTime: 'dateTimeFormat', + week: 'weekFormat', + month: 'monthFormat', +}; function getColumns({ showHour, showMinute, showSecond, use12Hours }) { let column = 0; @@ -22,22 +37,21 @@ function getColumns({ showHour, showMinute, showSecond, use12Hours }) { return column; } -export default function wrapPicker(Picker, props, defaultFormat) { +export default function wrapPicker(Picker, props, pickerType) { return { name: Picker.name, props: initDefaultProps(props, { - format: defaultFormat || 'YYYY-MM-DD', transitionName: 'slide-up', popupStyle: {}, locale: {}, - prefixCls: 'ant-calendar', - inputPrefixCls: 'ant-input', }), model: { prop: 'value', event: 'change', }, - + inject: { + configProvider: { default: () => ({}) }, + }, mounted() { const { autoFocus, disabled } = this; if (autoFocus && !disabled) { @@ -89,7 +103,24 @@ export default function wrapPicker(Picker, props, defaultFormat) { renderPicker(locale, localeCode) { const props = getOptionProps(this); - const { prefixCls, inputPrefixCls, size, showTime, disabled } = props; + const { + prefixCls: customizePrefixCls, + inputPrefixCls: customizeInputPrefixCls, + size, + showTime, + disabled, + format, + } = props; + const mergedPickerType = showTime ? `${pickerType}Time` : pickerType; + const mergedFormat = + format || + locale[LOCALE_FORMAT_MAPPING[mergedPickerType]] || + DEFAULT_FORMAT[mergedPickerType]; + + const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls; + const prefixCls = getPrefixCls('calendar', customizePrefixCls); + const inputPrefixCls = getPrefixCls('input', customizeInputPrefixCls); + const pickerClass = classNames(`${prefixCls}-picker`, { [`${prefixCls}-picker-${size}`]: !!size, }); @@ -121,6 +152,7 @@ export default function wrapPicker(Picker, props, defaultFormat) { const pickerProps = { props: { ...props, + format: mergedFormat, pickerClass, pickerInputClass, locale, diff --git a/components/modal/demo/confirm-router.md b/components/modal/demo/confirm-router.md index 1ffb0faa4..4ca07c19f 100644 --- a/components/modal/demo/confirm-router.md +++ b/components/modal/demo/confirm-router.md @@ -23,7 +23,7 @@ export default { for (let i = 0; i < 3; i += 1) { setTimeout(() => { this.$confirm({ - content: ( // JSX support + content: (