diff --git a/components/_util/props-util.js b/components/_util/props-util.js index 956dea91a..0e7e90219 100644 --- a/components/_util/props-util.js +++ b/components/_util/props-util.js @@ -1,3 +1,5 @@ +import isPlainObject from 'lodash.isplainobject' + const camelizeRE = /-(\w)/g const camelize = (str) => { return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '') @@ -176,7 +178,15 @@ export function filterEmpty (children = []) { return children.filter(c => c.tag || c.text.trim() !== '') } const initDefaultProps = (propTypes, defaultProps) => { - Object.keys(defaultProps).forEach(k => { propTypes[k] = propTypes[k].def(defaultProps[k]) }) + Object.keys(defaultProps).forEach(k => { + if (propTypes[k]) { + propTypes[k].def && (propTypes[k] = propTypes[k].def(defaultProps[k])) + } else { + throw new Error( + `not have ${k} prop`, + ) + } + }) return propTypes } @@ -186,11 +196,16 @@ export function mergeProps () { args.forEach((p, i) => { for (const [k, v] of Object.entries(p)) { props[k] = props[k] || {} - Object.assign(props[k], v) + if (isPlainObject(v)) { + Object.assign(props[k], v) + } else { + props[k] = v + } } }) return props } + export { hasProp, filterProps, diff --git a/components/date-picker/RangePicker.tsx b/components/date-picker/RangePicker.tsx deleted file mode 100644 index 65e9aa383..000000000 --- a/components/date-picker/RangePicker.tsx +++ /dev/null @@ -1,366 +0,0 @@ -/* tslint:disable jsx-no-multiline-js */ -import * as React from 'react'; -import * as moment from 'moment'; -import RangeCalendar from 'rc-calendar/lib/RangeCalendar'; -import RcDatePicker from 'rc-calendar/lib/Picker'; -import classNames from 'classnames'; -import Icon from '../icon'; -import warning from '../_util/warning'; -import callMoment from '../_util/callMoment'; -import { RangePickerValue, RangePickerPresetRange } from './interface'; - -export interface RangePickerState { - value?: RangePickerValue; - showDate?: RangePickerValue; - open?: boolean; - hoverValue?: RangePickerValue; -} - -function getShowDateFromValue(value: RangePickerValue) { - const [start, end] = value; - // value could be an empty array, then we should not reset showDate - if (!start && !end) { - return; - } - const newEnd = end && end.isSame(start, 'month') ? end.clone().add(1, 'month') : end; - return [start, newEnd] as RangePickerValue; -} - -function formatValue(value: moment.Moment | undefined, format: string): string { - return (value && value.format(format)) || ''; -} - -function pickerValueAdapter(value?: moment.Moment | RangePickerValue): RangePickerValue | undefined { - if (!value) { - return; - } - if (Array.isArray(value)) { - return value; - } - return [value, value.clone().add(1, 'month')]; -} - -function isEmptyArray(arr: any) { - if (Array.isArray(arr)) { - return arr.length === 0 || arr.every(i => !i); - } - return false; -} - -function fixLocale(value: RangePickerValue | undefined, localeCode: string) { - if (!localeCode) { - return; - } - if (!value || value.length === 0) { - return; - } - if (value[0]) { - value[0]!.locale(localeCode); - } - if (value[1]) { - value[1]!.locale(localeCode); - } -} - -export default class RangePicker extends React.Component { - static defaultProps = { - prefixCls: 'ant-calendar', - allowClear: true, - showToday: false, - }; - - private picker: HTMLSpanElement; - - constructor(props: any) { - super(props); - const value = props.value || props.defaultValue || []; - if ( - value[0] && !moment.isMoment(value[0]) || - value[1] && !moment.isMoment(value[1]) - ) { - throw new Error( - 'The value/defaultValue of RangePicker must be a moment object array after `antd@2.0`, ' + - 'see: https://u.ant.design/date-picker-value', - ); - } - const pickerValue = !value || isEmptyArray(value) ? props.defaultPickerValue : value; - this.state = { - value, - showDate: pickerValueAdapter(pickerValue || callMoment(moment)), - open: props.open, - hoverValue: [], - }; - } - - componentWillReceiveProps(nextProps: any) { - if ('value' in nextProps) { - const state = this.state; - const value = nextProps.value || []; - this.setState({ - value, - showDate: getShowDateFromValue(value) || state.showDate, - }); - } - if ('open' in nextProps) { - this.setState({ - open: nextProps.open, - }); - } - } - - clearSelection = (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - this.setState({ value: [] }); - this.handleChange([]); - } - - clearHoverValue = () => this.setState({ hoverValue: [] }); - - handleChange = (value: RangePickerValue) => { - const props = this.props; - if (!('value' in props)) { - this.setState(({ showDate }) => ({ - value, - showDate: getShowDateFromValue(value) || showDate, - })); - } - props.onChange(value, [ - formatValue(value[0], props.format), - formatValue(value[1], props.format), - ]); - } - - handleOpenChange = (open: boolean) => { - if (!('open' in this.props)) { - this.setState({ open }); - } - - if (open === false) { - this.clearHoverValue(); - } - - const { onOpenChange } = this.props; - if (onOpenChange) { - onOpenChange(open); - } - } - - handleShowDateChange = (showDate: RangePickerValue) => this.setState({ showDate }); - - handleHoverChange = (hoverValue: any) => this.setState({ hoverValue }); - - handleRangeMouseLeave = () => { - if (this.state.open) { - this.clearHoverValue(); - } - } - - handleCalendarInputSelect = (value: RangePickerValue) => { - if (!value[0]) { - return; - } - this.setState(({ showDate }) => ({ - value, - showDate: getShowDateFromValue(value) || showDate, - })); - } - - handleRangeClick = (value: RangePickerPresetRange) => { - if (typeof value === 'function') { - value = value(); - } - - this.setValue(value, true); - - const { onOk } = this.props; - if (onOk) { - onOk(value); - } - } - - setValue(value: RangePickerValue, hidePanel?: boolean) { - this.handleChange(value); - if ((hidePanel || !this.props.showTime) && !('open' in this.props)) { - this.setState({ open: false }); - } - } - - focus() { - this.picker.focus(); - } - - blur() { - this.picker.blur(); - } - - savePicker = (node: HTMLSpanElement) => { - this.picker = node; - } - - renderFooter = (...args: any[]) => { - const { prefixCls, ranges, renderExtraFooter } = this.props; - if (!ranges && !renderExtraFooter) { - return null; - } - const customFooter = renderExtraFooter ? ( -
- {renderExtraFooter(...args)} -
- ) : null; - const operations = Object.keys(ranges || {}).map((range) => { - const value = ranges[range]; - return ( - this.handleRangeClick(value)} - onMouseEnter={() => this.setState({ hoverValue: value })} - onMouseLeave={this.handleRangeMouseLeave} - > - {range} - - ); - }); - const rangeNode = ( -
- {operations} -
- ); - return [rangeNode, customFooter]; - } - - render() { - const { state, props } = this; - const { value, showDate, hoverValue, open } = state; - const { - prefixCls, popupStyle, style, - disabledDate, disabledTime, - showTime, showToday, - ranges, onOk, locale, localeCode, format, - dateRender, onCalendarChange, - } = props; - - fixLocale(value, localeCode); - fixLocale(showDate, localeCode); - - warning(!('onOK' in props), 'It should be `RangePicker[onOk]`, instead of `onOK`!'); - - const calendarClassName = classNames({ - [`${prefixCls}-time`]: showTime, - [`${prefixCls}-range-with-ranges`]: ranges, - }); - - // 需要选择时间时,点击 ok 时才触发 onChange - let pickerChangeHandler = { - onChange: this.handleChange, - }; - let calendarProps: any = { - onOk: this.handleChange, - }; - if (props.timePicker) { - pickerChangeHandler.onChange = changedValue => this.handleChange(changedValue); - } else { - calendarProps = {}; - } - if ('mode' in props) { - calendarProps.mode = props.mode; - } - - const startPlaceholder = ('placeholder' in props) - ? props.placeholder[0] : locale.lang.rangePlaceholder[0]; - const endPlaceholder = ('placeholder' in props) - ? props.placeholder[1] : locale.lang.rangePlaceholder[1]; - - const calendar = ( - - ); - - // default width for showTime - const pickerStyle = {} as any; - if (props.showTime) { - pickerStyle.width = (style && style.width) || 350; - } - - const clearIcon = (!props.disabled && props.allowClear && value && (value[0] || value[1])) ? ( - - ) : null; - - const input = ({ value: inputValue }: { value: any }) => { - const start = inputValue[0]; - const end = inputValue[1]; - return ( - - - ~ - - {clearIcon} - - - ); - }; - - return ( - - - {input} - - - ); - } -} diff --git a/components/date-picker/RangePicker.vue b/components/date-picker/RangePicker.vue new file mode 100644 index 000000000..e6cdd5ea1 --- /dev/null +++ b/components/date-picker/RangePicker.vue @@ -0,0 +1,365 @@ + diff --git a/components/date-picker/WeekPicker.vue b/components/date-picker/WeekPicker.vue index 40ef26348..2b725249a 100644 --- a/components/date-picker/WeekPicker.vue +++ b/components/date-picker/WeekPicker.vue @@ -3,8 +3,9 @@ import * as moment from 'moment' import Calendar from '../vc-calendar' import VcDatePicker from '../vc-calendar/src/Picker' import Icon from '../icon' -import { hasProp, getOptionProps } from '../_util/props-util' +import { hasProp, getOptionProps, initDefaultProps } from '../_util/props-util' import BaseMixin from '../_util/BaseMixin' +import { WeexPickerProps } from './interface' function formatValue (value, format) { return (value && value.format(format)) || '' @@ -18,6 +19,10 @@ export default { // }; // private input: any; + props: initDefaultProps(WeexPickerProps(), { + format: 'YYYY-wo', + allowClear: true, + }), name: 'WeekPicker', mixins: [BaseMixin], data () { @@ -85,7 +90,7 @@ export default { const { prefixCls, disabled, pickerClass, popupStyle, pickerInputClass, format, allowClear, locale, localeCode, disabledDate, - sValue: pickerValue, $listeners, + sValue: pickerValue, $listeners, $scopedSlots, } = this const { focus = noop, blur = noop } = $listeners @@ -94,11 +99,11 @@ export default { } const placeholder = hasProp(this, 'placeholder') ? this.placeholder : locale.lang.placeholder - + const weekDateRender = this.dateRender || $scopedSlots.dateRender || this.weekDateRender const calendar = ( ) @@ -155,8 +166,6 @@ export default function createPicker (TheCalendar) { value={(inputValue && inputValue.format(props.format)) || ''} placeholder={placeholder} class={props.pickerInputClass} - onFocus={focus} - onBlur={blur} /> {clearIcon} @@ -179,8 +188,8 @@ export default function createPicker (TheCalendar) { return ( +#### 基本 最简单的用法,在浮层中可以选择或者输入日期。 + -## en-US - + +#### Basic Basic use case. Users can select or input a date in panel. + -````jsx -import { DatePicker } from 'antd'; -const { MonthPicker, RangePicker, WeekPicker } = DatePicker; - -function onChange(date, dateString) { - console.log(date, dateString); -} - -ReactDOM.render( +```html + + +``` + + diff --git a/components/date-picker/demo/date-render.md b/components/date-picker/demo/date-render.md index 278f76f41..4e3b0211e 100644 --- a/components/date-picker/demo/date-render.md +++ b/components/date-picker/demo/date-render.md @@ -1,52 +1,52 @@ ---- -order: 12 -title: - zh-CN: 定制日期单元格 - en-US: Customized Date Rendering ---- - -## zh-CN + +#### 定制日期单元格 使用 `dateRender` 可以自定义日期单元格的内容和样式。 + -## en-US - + +#### Customized Date Rendering We can customize the rendering of date cells in the calendar by providing a `dateRender` function to `DatePicker`. + -````jsx -import { DatePicker } from 'antd'; -const { RangePicker } = DatePicker; - -ReactDOM.render( +```html +