diff --git a/components/date-picker/RangePicker.jsx b/components/date-picker/RangePicker.jsx index f65d572f6..e62240197 100644 --- a/components/date-picker/RangePicker.jsx +++ b/components/date-picker/RangePicker.jsx @@ -8,8 +8,9 @@ import Icon from '../icon' import Tag from '../tag' import interopDefault from '../_util/interopDefault' import { RangePickerProps } from './interface' -import { hasProp, getOptionProps, initDefaultProps, mergeProps } from '../_util/props-util' +import { hasProp, getOptionProps, initDefaultProps, mergeProps, getComponentFromProp, isValidElement } from '../_util/props-util' import BaseMixin from '../_util/BaseMixin' +import { cloneElement } from '../_util/vnode' function noop () {} function getShowDateFromValue (value) { const [start, end] = value @@ -130,6 +131,7 @@ export default { formatValue(value[0], this.format), formatValue(value[1], this.format), ]) + this.focus() }, handleOpenChange (open) { @@ -174,6 +176,7 @@ export default { this.setValue(value, true) this.$emit('ok', value) + this.$emit('openChange', false) }, setValue (value, hidePanel) { @@ -224,17 +227,18 @@ export default { ) }) - const rangeNode = ( + const rangeNode = (operations && operations.length > 0) ? ( - ) + ) : null return [rangeNode, customFooter] }, }, render () { const props = getOptionProps(this) + let suffixIcon = getComponentFromProp(this, 'suffixIcon') + suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon const { sValue: value, sShowDate: showDate, sHoverValue: hoverValue, sOpen: open, $listeners, $scopedSlots } = this const { calendarChange = noop, ok = noop, focus = noop, blur = noop, panelChange = noop } = $listeners const { @@ -296,7 +300,7 @@ export default { ok: ok, valueChange: this.handleShowDateChange, hoverChange: this.handleHoverChange, - panelChange: panelChange, + panelChange, inputSelect: this.handleCalendarInputSelect, }, class: calendarClassName, @@ -316,12 +320,24 @@ export default { const clearIcon = (!props.disabled && props.allowClear && value && (value[0] || value[1])) ? ( ) : null + const inputIcon = suffixIcon && ( + isValidElement(suffixIcon) + ? cloneElement( + suffixIcon, + { + class: `${prefixCls}-picker-icon`, + }, + ) : {suffixIcon}) || ( + + ) + const input = ({ value: inputValue }) => { const start = inputValue[0] const end = inputValue[1] @@ -345,7 +361,7 @@ export default { tabIndex={-1} /> {clearIcon} - + {inputIcon} ) } diff --git a/components/date-picker/WeekPicker.jsx b/components/date-picker/WeekPicker.jsx index bd3fa6bf6..d7526e6bf 100644 --- a/components/date-picker/WeekPicker.jsx +++ b/components/date-picker/WeekPicker.jsx @@ -3,10 +3,11 @@ import * as moment from 'moment' import Calendar from '../vc-calendar' import VcDatePicker from '../vc-calendar/src/Picker' import Icon from '../icon' -import { hasProp, getOptionProps, initDefaultProps } from '../_util/props-util' +import { hasProp, getOptionProps, initDefaultProps, getComponentFromProp, isValidElement } from '../_util/props-util' import BaseMixin from '../_util/BaseMixin' import { WeekPickerProps } from './interface' import interopDefault from '../_util/interopDefault' +import { cloneElement } from '../_util/vnode' function formatValue (value, format) { return (value && value.format(format)) || '' @@ -74,6 +75,7 @@ export default { this.setState({ sValue: value }) } this.$emit('change', value, formatValue(value, this.format)) + this.focus() }, clearSelection (e) { e.preventDefault() @@ -92,6 +94,8 @@ export default { render () { const props = getOptionProps(this) + let suffixIcon = getComponentFromProp(this, 'suffixIcon') + suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon const { prefixCls, disabled, pickerClass, popupStyle, pickerInputClass, format, allowClear, locale, localeCode, disabledDate, @@ -119,11 +123,24 @@ export default { ) const clearIcon = (!disabled && allowClear && this.sValue) ? ( ) : null + + const inputIcon = suffixIcon && ( + isValidElement(suffixIcon) + ? cloneElement( + suffixIcon, + { + class: `${prefixCls}-picker-icon`, + }, + ) : {suffixIcon}) || ( + + ) + const input = ({ value }) => { return ( @@ -138,7 +155,7 @@ export default { onBlur={blur} /> {clearIcon} - + {inputIcon} ) } diff --git a/components/date-picker/__tests__/MonthPicker.test.js b/components/date-picker/__tests__/MonthPicker.test.js index 2e115e9af..f0cf2e6c5 100644 --- a/components/date-picker/__tests__/MonthPicker.test.js +++ b/components/date-picker/__tests__/MonthPicker.test.js @@ -1,8 +1,26 @@ +import { mount } from '@vue/test-utils' +import { asyncExpect } from '@/tests/utils' +import moment from 'moment' import DatePicker from '..' import focusTest from '../../../tests/shared/focusTest' +import { openPanel, $$ } from './utils' const { MonthPicker } = DatePicker describe('MonthPicker', () => { focusTest(MonthPicker) + it('reset select item when popup close', async () => { + const wrapper = mount(MonthPicker, { + propsData: { value: moment('2018-07-01') }, + sync: false, + attachToDocument: true, + }) + await asyncExpect(() => { + openPanel(wrapper) + }) + await asyncExpect(() => { + $$('.ant-calendar-month-panel-month')[0].click() + $$('.ant-calendar-month-panel-cell')[6].getAttribute('class').split(' ').includes('ant-calendar-month-panel-selected-cell') + }, 0) + }) }) diff --git a/components/date-picker/__tests__/RangePicker.test.js b/components/date-picker/__tests__/RangePicker.test.js index 84abd5dde..6d0854b21 100644 --- a/components/date-picker/__tests__/RangePicker.test.js +++ b/components/date-picker/__tests__/RangePicker.test.js @@ -325,4 +325,26 @@ describe('RangePicker', () => { }).not.toThrow() }) }) + // https://github.com/ant-design/ant-design/issues/11631 + it('triggers onOpenChange when click on preset range', async () => { + const handleOpenChange = jest.fn() + const range = [moment().subtract(2, 'd'), moment()] + const wrapper = mount({ + render () { + return + }, + }, { + sync: false, + attachToDocument: true, + }) + await asyncExpect(() => { + wrapper.find('.ant-calendar-picker-input').trigger('click') + }) + await asyncExpect(() => { + $$('.ant-calendar-range-quick-selector .ant-tag')[0].click() + }, 0) + await asyncExpect(() => { + expect(handleOpenChange).toBeCalledWith(false) + }) + }) }) diff --git a/components/date-picker/__tests__/__snapshots__/demo.test.js.snap b/components/date-picker/__tests__/__snapshots__/demo.test.js.snap index 1e6d91c61..6c1e5f529 100644 --- a/components/date-picker/__tests__/__snapshots__/demo.test.js.snap +++ b/components/date-picker/__tests__/__snapshots__/demo.test.js.snap @@ -1,30 +1,77 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`renders ./components/date-picker/demo/basic.md correctly 1`] = `


~
`; - -exports[`renders ./components/date-picker/demo/date-render.md correctly 1`] = `
~
`; - -exports[`renders ./components/date-picker/demo/disabled.md correctly 1`] = `


~
`; - -exports[`renders ./components/date-picker/demo/disabled-date.md correctly 1`] = `


~
`; - -exports[`renders ./components/date-picker/demo/extra-footer.md correctly 1`] = `
~ ~
`; - -exports[`renders ./components/date-picker/demo/format.md correctly 1`] = ` -


~ -
+exports[`renders ./components/date-picker/demo/basic.md correctly 1`] = ` +


~
`; -exports[`renders ./components/date-picker/demo/mode.md correctly 1`] = `

~
`; +exports[`renders ./components/date-picker/demo/date-render.md correctly 1`] = ` +
~
+`; -exports[`renders ./components/date-picker/demo/presetted-ranges.md correctly 1`] = `
~
~
`; +exports[`renders ./components/date-picker/demo/disabled.md correctly 1`] = ` +


~
+`; + +exports[`renders ./components/date-picker/demo/disabled-date.md correctly 1`] = ` +


~
+`; + +exports[`renders ./components/date-picker/demo/extra-footer.md correctly 1`] = ` +
~ ~
+`; + +exports[`renders ./components/date-picker/demo/format.md correctly 1`] = ` +


~
+`; + +exports[`renders ./components/date-picker/demo/mode.md correctly 1`] = ` +

~
+`; + +exports[`renders ./components/date-picker/demo/presetted-ranges.md correctly 1`] = ` +
~
~
+`; exports[`renders ./components/date-picker/demo/size.md correctly 1`] = `
-


-


~
+




~
+ `; -exports[`renders ./components/date-picker/demo/start-end.md correctly 1`] = `
`; +exports[`renders ./components/date-picker/demo/start-end.md correctly 1`] = `
`; -exports[`renders ./components/date-picker/demo/time.md correctly 1`] = `

~
`; +exports[`renders ./components/date-picker/demo/suffix.md correctly 1`] = ` +


~

ab

ab

~ ab
ab
+`; + +exports[`renders ./components/date-picker/demo/time.md correctly 1`] = ` +

~
+`; diff --git a/components/date-picker/createPicker.js b/components/date-picker/createPicker.js index 14ba81bb9..3ed0218c3 100644 --- a/components/date-picker/createPicker.js +++ b/components/date-picker/createPicker.js @@ -7,7 +7,8 @@ import classNames from 'classnames' import Icon from '../icon' import interopDefault from '../_util/interopDefault' import BaseMixin from '../_util/BaseMixin' -import { hasProp, getOptionProps, initDefaultProps, mergeProps } from '../_util/props-util' +import { hasProp, getOptionProps, initDefaultProps, mergeProps, getComponentFromProp, isValidElement } from '../_util/props-util' +import { cloneElement } from '../_util/vnode' // export const PickerProps = { // value?: moment.Moment; @@ -44,14 +45,26 @@ export default function createPicker (TheCalendar, props) { return { sValue: value, showDate: value, + _open: !!this.open, } }, watch: { + open (val) { + const props = getOptionProps(this) + const state = {} + state._open = val + if ('value' in props && !val && props.value !== this.showDate) { + state.showDate = props.value + } + this.setState(state) + }, value (val) { - this.setState({ - sValue: val, - showDate: val, - }) + const state = {} + state.sValue = val + if (val !== this.sValue) { + state.showDate = val + } + this.setState(state) }, }, methods: { @@ -79,12 +92,19 @@ export default function createPicker (TheCalendar, props) { }) } this.$emit('change', value, (value && value.format(this.format)) || '') + this.focus() }, handleCalendarChange (value) { this.setState({ showDate: value }) }, - + handleOpenChange (open) { + const props = getOptionProps(this) + if (!('open' in props)) { + this.setState({ _open: open }) + } + this.$emit('openChange', open) + }, focus () { this.$refs.input.focus() }, @@ -101,7 +121,10 @@ export default function createPicker (TheCalendar, props) { }, render () { - const { sValue: value, showDate, $listeners, $scopedSlots } = this + const { $listeners, $scopedSlots } = this + const { sValue: value, showDate, _open: open } = this.$data + let suffixIcon = getComponentFromProp(this, 'suffixIcon') + 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 @@ -123,9 +146,11 @@ export default function createPicker (TheCalendar, props) { const pickerProps = { props: {}, on: {}} const calendarProps = { props: {}, on: {}} + const pickerStyle = {} if (props.showTime) { // fix https://github.com/ant-design/ant-design/issues/1902 calendarProps.on.select = this.handleChange + pickerStyle.width = '195px' } else { pickerProps.on.change = this.handleChange } @@ -150,7 +175,7 @@ export default function createPicker (TheCalendar, props) { }, on: { ok: ok, - panelChange: panelChange, + panelChange, change: this.handleCalendarChange, }, class: calendarClassName, @@ -164,12 +189,24 @@ export default function createPicker (TheCalendar, props) { const clearIcon = (!props.disabled && props.allowClear && value) ? ( ) : null + const inputIcon = suffixIcon && ( + isValidElement(suffixIcon) + ? cloneElement( + suffixIcon, + { + class: `${prefixCls}-picker-icon`, + }, + ) : {suffixIcon}) || ( + + ) + const input = ({ value: inputValue }) => (
{clearIcon} - + {inputIcon}
) const vcDatePickerProps = { @@ -197,12 +234,15 @@ export default function createPicker (TheCalendar, props) { on: { ...omit($listeners, 'change'), ...pickerProps.on, + open, + onOpenChange: this.handleOpenChange, }, style: props.popupStyle, } return (