add date-picker demo

pull/165/head
tjz 2018-03-17 21:38:29 +08:00
parent 041fd349a4
commit c953ca07bb
24 changed files with 686 additions and 613 deletions

View File

@ -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] || {}
if (isPlainObject(v)) {
Object.assign(props[k], v)
} else {
props[k] = v
}
}
})
return props
}
export {
hasProp,
filterProps,

View File

@ -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<any, RangePickerState> {
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<HTMLElement>) => {
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 ? (
<div className={`${prefixCls}-footer-extra`} key="extra">
{renderExtraFooter(...args)}
</div>
) : null;
const operations = Object.keys(ranges || {}).map((range) => {
const value = ranges[range];
return (
<a
key={range}
onClick={() => this.handleRangeClick(value)}
onMouseEnter={() => this.setState({ hoverValue: value })}
onMouseLeave={this.handleRangeMouseLeave}
>
{range}
</a>
);
});
const rangeNode = (
<div className={`${prefixCls}-footer-extra ${prefixCls}-range-quick-selector`} key="range">
{operations}
</div>
);
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 = (
<RangeCalendar
{...calendarProps}
onChange={onCalendarChange}
format={format}
prefixCls={prefixCls}
className={calendarClassName}
renderFooter={this.renderFooter}
timePicker={props.timePicker}
disabledDate={disabledDate}
disabledTime={disabledTime}
dateInputPlaceholder={[startPlaceholder, endPlaceholder]}
locale={locale.lang}
onOk={onOk}
dateRender={dateRender}
value={showDate}
onValueChange={this.handleShowDateChange}
hoverValue={hoverValue}
onHoverChange={this.handleHoverChange}
onPanelChange={props.onPanelChange}
showToday={showToday}
onInputSelect={this.handleCalendarInputSelect}
/>
);
// 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])) ? (
<Icon
type="cross-circle"
className={`${prefixCls}-picker-clear`}
onClick={this.clearSelection}
/>
) : null;
const input = ({ value: inputValue }: { value: any }) => {
const start = inputValue[0];
const end = inputValue[1];
return (
<span className={props.pickerInputClass}>
<input
disabled={props.disabled}
readOnly
value={(start && start.format(props.format)) || ''}
placeholder={startPlaceholder}
className={`${prefixCls}-range-picker-input`}
tabIndex={-1}
/>
<span className={`${prefixCls}-range-picker-separator`}> ~ </span>
<input
disabled={props.disabled}
readOnly
value={(end && end.format(props.format)) || ''}
placeholder={endPlaceholder}
className={`${prefixCls}-range-picker-input`}
tabIndex={-1}
/>
{clearIcon}
<span className={`${prefixCls}-picker-icon`} />
</span>
);
};
return (
<span
ref={this.savePicker}
id={props.id}
className={classNames(props.className, props.pickerClass)}
style={{ ...style, ...pickerStyle }}
tabIndex={props.disabled ? -1 : 0}
onFocus={props.onFocus}
onBlur={props.onBlur}
>
<RcDatePicker
{...props}
{...pickerChangeHandler}
calendar={calendar}
value={value}
open={open}
onOpenChange={this.handleOpenChange}
prefixCls={`${prefixCls}-picker-container`}
style={popupStyle}
>
{input}
</RcDatePicker>
</span>
);
}
}

View File

@ -0,0 +1,365 @@
<script>
import * as moment from 'moment'
import RangeCalendar from '../vc-calendar/src/RangeCalendar'
import VcDatePicker from '../vc-calendar/src/Picker'
import classNames from 'classnames'
import Icon from '../icon'
import callMoment from '../_util/callMoment'
import { RangePickerProps } from './interface'
import { hasProp, getOptionProps, initDefaultProps, mergeProps } from '../_util/props-util'
import BaseMixin from '../_util/BaseMixin'
function noop () {}
function getShowDateFromValue (value) {
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]
}
function formatValue (value, format) {
return (value && value.format(format)) || ''
}
function pickerValueAdapter (value) {
if (!value) {
return
}
if (Array.isArray(value)) {
return value
}
return [value, value.clone().add(1, 'month')]
}
function isEmptyArray (arr) {
if (Array.isArray(arr)) {
return arr.length === 0 || arr.every(i => !i)
}
return false
}
function fixLocale (value, localeCode) {
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 {
mixins: [BaseMixin],
name: 'RangePicker',
props: initDefaultProps(RangePickerProps(), {
prefixCls: 'ant-calendar',
allowClear: true,
showToday: false,
}),
data () {
const value = this.value || this.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) ? this.defaultPickerValue : value
return {
sValue: value,
sShowDate: pickerValueAdapter(pickerValue || callMoment(moment)),
sOpen: this.open,
sHoverValue: [],
}
},
watch: {
value (val) {
const value = val || []
this.setState({
sValue: value,
sShowDate: getShowDateFromValue(value) || this.sShowDate,
})
},
open (val) {
this.setState({
sOpen: val,
})
},
},
methods: {
clearSelection (e) {
e.preventDefault()
e.stopPropagation()
this.setState({ sValue: [] })
this.handleChange([])
},
clearHoverValue () {
this.setState({ sHoverValue: [] })
},
handleChange (value) {
if (!hasProp(this, 'value')) {
this.setState(({ sShowDate }) => ({
sValue: value,
sShowDate: getShowDateFromValue(value) || sShowDate,
}))
}
this.$emit('change', value, [
formatValue(value[0], this.format),
formatValue(value[1], this.format),
])
},
handleOpenChange (open) {
if (!hasProp(this, 'open')) {
this.setState({ sOpen: open })
}
if (open === false) {
this.clearHoverValue()
}
this.$emit('openChange', open)
},
handleShowDateChange (showDate) {
this.setState({ sShowDate: showDate })
},
handleHoverChange (hoverValue) {
this.setState({ sHoverValue: hoverValue })
},
handleRangeMouseLeave () {
if (this.sOpen) {
this.clearHoverValue()
}
},
handleCalendarInputSelect (value) {
if (!value[0]) {
return
}
this.setState(({ sShowDate }) => ({
sValue: value,
sShowDate: getShowDateFromValue(value) || sShowDate,
}))
},
handleRangeClick (value) {
if (typeof value === 'function') {
value = value()
}
this.setValue(value, true)
this.$emit('ok', value)
},
setValue (value, hidePanel) {
this.handleChange(value)
if ((hidePanel || !this.showTime) && !hasProp(this, 'open')) {
this.setState({ sOpen: false })
}
},
focus () {
this.$refs.picker.focus()
},
blur () {
this.$refs.picker.blur()
},
renderFooter (...args) {
const { prefixCls, ranges, renderExtraFooter } = this
if (!ranges && !renderExtraFooter) {
return null
}
const customFooter = renderExtraFooter ? (
<div class={`${prefixCls}-footer-extra`} key='extra'>
{renderExtraFooter(...args)}
</div>
) : null
const operations = Object.keys(ranges || {}).map((range) => {
const value = ranges[range]
return (
<a
key={range}
onClick={() => this.handleRangeClick(value)}
onMouseenter={() => this.setState({ sHoverValue: value })}
onMouseleave={this.handleRangeMouseLeave}
>
{range}
</a>
)
})
const rangeNode = (
<div class={`${prefixCls}-footer-extra ${prefixCls}-range-quick-selector`} key='range'>
{operations}
</div>
)
return [rangeNode, customFooter]
},
},
render () {
const props = getOptionProps(this)
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 {
prefixCls, popupStyle,
disabledDate, disabledTime,
showTime, showToday,
ranges, locale, localeCode, format,
} = props
const dateRender = props.dateRender || $scopedSlots.dateRender
fixLocale(value, localeCode)
fixLocale(showDate, localeCode)
const calendarClassName = classNames({
[`${prefixCls}-time`]: showTime,
[`${prefixCls}-range-with-ranges`]: ranges,
})
// ok onChange
const pickerChangeHandler = {
on: {
change: this.handleChange,
},
}
let calendarProps = {
on: {
ok: this.handleChange,
}, props: {},
}
if (props.timePicker) {
pickerChangeHandler.on.change = changedValue => this.handleChange(changedValue)
} else {
calendarProps = { on: {}, props: {}}
}
if ('mode' in props) {
calendarProps.props.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 rangeCalendarProps = mergeProps(calendarProps, {
props: {
format: format,
prefixCls: prefixCls,
renderFooter: this.renderFooter,
timePicker: props.timePicker,
disabledDate: disabledDate,
disabledTime: disabledTime,
dateInputPlaceholder: [startPlaceholder, endPlaceholder],
locale: locale.lang,
dateRender: dateRender,
value: showDate,
hoverValue: hoverValue,
showToday: showToday,
},
on: {
change: calendarChange,
ok: ok,
valueChange: this.handleShowDateChange,
hoverChange: this.handleHoverChange,
panelChange: panelChange,
inputSelect: this.handleCalendarInputSelect,
},
class: calendarClassName,
scopedSlots: $scopedSlots,
})
const calendar = (
<RangeCalendar
{...rangeCalendarProps}
/>
)
// default width for showTime
const pickerStyle = {}
if (props.showTime) {
pickerStyle.width = '350px'
}
const clearIcon = (!props.disabled && props.allowClear && value && (value[0] || value[1])) ? (
<Icon
type='cross-circle'
class={`${prefixCls}-picker-clear`}
onClick={this.clearSelection}
/>
) : null
const input = ({ value: inputValue }) => {
const start = inputValue[0]
const end = inputValue[1]
return (
<span class={props.pickerInputClass}>
<input
disabled={props.disabled}
readOnly
value={(start && start.format(props.format)) || ''}
placeholder={startPlaceholder}
class={`${prefixCls}-range-picker-input`}
tabIndex={-1}
/>
<span class={`${prefixCls}-range-picker-separator`}> ~ </span>
<input
disabled={props.disabled}
readOnly
value={(end && end.format(props.format)) || ''}
placeholder={endPlaceholder}
class={`${prefixCls}-range-picker-input`}
tabIndex={-1}
/>
{clearIcon}
<span class={`${prefixCls}-picker-icon`} />
</span>
)
}
const vcDatePickerProps = mergeProps({
props,
on: $listeners,
}, pickerChangeHandler, {
props: {
calendar: calendar,
value: value,
open: open,
prefixCls: `${prefixCls}-picker-container`,
},
on: {
openChange: this.handleOpenChange,
},
style: popupStyle,
})
return (
<span
ref='picker'
class={props.pickerClass}
style={pickerStyle}
tabIndex={props.disabled ? -1 : 0}
onFocus={focus}
onBlur={blur}
>
<VcDatePicker
{...vcDatePickerProps}
>
{input}
</VcDatePicker>
</span>
)
},
}
</script>

View File

@ -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 = (
<Calendar
showWeekNumber
dateRender={this.weekDateRender}
dateRender={weekDateRender}
prefixCls={prefixCls}
format={format}
locale={locale.lang}

View File

@ -6,14 +6,14 @@ import classNames from 'classnames'
import Icon from '../icon'
import callMoment from '../_util/callMoment'
import BaseMixin from '../_util/BaseMixin'
import { hasProp, getOptionProps } from '../_util/props-util'
import { hasProp, getOptionProps, initDefaultProps, mergeProps } from '../_util/props-util'
// export const PickerProps = {
// value?: moment.Moment;
// prefixCls: string;
// }
function noop () {}
export default function createPicker (TheCalendar) {
export default function createPicker (TheCalendar, props) {
return {
// static defaultProps = {
// prefixCls: 'ant-calendar',
@ -22,6 +22,11 @@ export default function createPicker (TheCalendar) {
// };
// private input: any;
props: initDefaultProps(props, {
prefixCls: 'ant-calendar',
allowClear: true,
showToday: true,
}),
mixins: [BaseMixin],
data () {
const value = this.value || this.defaultValue
@ -84,11 +89,11 @@ export default function createPicker (TheCalendar) {
},
render () {
const { sValue: value, showDate, $listeners } = this
const { sValue: value, showDate, $listeners, $scopedSlots } = this
const { panelChange = noop, focus = noop, blur = noop, ok = noop } = $listeners
const props = getOptionProps(this)
const { prefixCls, locale, localeCode } = props
const dateRender = props.dateRender || $scopedSlots.dateRender
const placeholder = ('placeholder' in props)
? props.placeholder : locale.lang.placeholder
@ -114,27 +119,33 @@ export default function createPicker (TheCalendar) {
if ('mode' in props) {
calendarProps.props.mode = props.mode
}
const theCalendarProps = mergeProps(calendarProps, {
props: {
disabledDate: props.disabledDate,
disabledTime,
locale: locale.lang,
timePicker: props.timePicker,
defaultValue: props.defaultPickerValue || callMoment(moment),
dateInputPlaceholder: placeholder,
prefixCls,
dateRender,
format: props.format,
showToday: props.showToday,
monthCellContentRender: props.monthCellContentRender,
renderFooter: this.renderFooter,
value: showDate,
},
on: {
ok: ok,
panelChange: panelChange,
change: this.handleCalendarChange,
},
class: calendarClassName,
scopedSlots: $scopedSlots,
})
const calendar = (
<TheCalendar
{...calendarProps}
disabledDate={props.disabledDate}
disabledTime={disabledTime}
locale={locale.lang}
timePicker={props.timePicker}
defaultValue={props.defaultPickerValue || callMoment(moment)}
dateInputPlaceholder={placeholder}
prefixCls={prefixCls}
class={calendarClassName}
onOk={ok}
dateRender={props.dateRender}
format={props.format}
showToday={props.showToday}
monthCellContentRender={props.monthCellContentRender}
renderFooter={this.renderFooter}
onPanelChange={panelChange}
onChange={this.handleCalendarChange}
value={showDate}
{...theCalendarProps}
/>
)
@ -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}
<span class={`${prefixCls}-picker-icon`} />
@ -179,8 +188,8 @@ export default function createPicker (TheCalendar) {
return (
<span
class={props.pickerClass}
// onFocus={focus}
// onBlur={blur}
onFocus={focus}
onBlur={blur}
>
<VcDatePicker
{...vcDatePickerProps}

View File

@ -1,35 +1,35 @@
---
order: 0
title:
zh-CN: 基本
en-US: Basic
---
## zh-CN
<cn>
#### 基本
最简单的用法,在浮层中可以选择或者输入日期。
</cn>
## en-US
<us>
#### Basic
Basic use case. Users can select or input a date in panel.
</us>
````jsx
import { DatePicker } from 'antd';
const { MonthPicker, RangePicker, WeekPicker } = DatePicker;
function onChange(date, dateString) {
```html
<template>
<div>
<a-date-picker @change="onChange" />
<br />
<a-month-picker @change="onChange" placeholder="Select month" />
<br />
<a-range-picker @change="onChange" />
<br />
<a-week-picker @change="onChange" placeholder="Select week" />
</div>
</template>
<script>
export default {
methods: {
onChange(date, dateString) {
console.log(date, dateString);
}
}
}
</script>
```
ReactDOM.render(
<div>
<DatePicker onChange={onChange} />
<br />
<MonthPicker onChange={onChange} placeholder="Select month" />
<br />
<RangePicker onChange={onChange} />
<br />
<WeekPicker onChange={onChange} placeholder="Select week" />
</div>
, mountNode);
````

View File

@ -1,52 +1,52 @@
---
order: 12
title:
zh-CN: 定制日期单元格
en-US: Customized Date Rendering
---
## zh-CN
<cn>
#### 定制日期单元格
使用 `dateRender` 可以自定义日期单元格的内容和样式。
</cn>
## en-US
<us>
#### Customized Date Rendering
We can customize the rendering of date cells in the calendar by providing a `dateRender` function to `DatePicker`.
</us>
````jsx
import { DatePicker } from 'antd';
const { RangePicker } = DatePicker;
ReactDOM.render(
```html
<template>
<div>
<DatePicker
dateRender={(current) => {
<a-date-picker>
<template slot="dateRender" slot-scope="current, today">
<div class="ant-calendar-date" :style="getCurrentStyle(current, today)">
{{current.date()}}
</div>
</tempalte>
</a-date-picker>
<a-range-picker>
<template slot="dateRender" slot-scope="current">
<div class="ant-calendar-date" :style="getCurrentStyle(current)">
{{current.date()}}
</div>
</tempalte>
</a-range-picker>
<a-week-picker>
<template slot="dateRender" slot-scope="current">
<div class="ant-calendar-date" :style="getCurrentStyle(current)">
{{current.date()}}
</div>
</tempalte>
</a-week-picker>
</div>
</template>
<script>
export default {
methods: {
getCurrentStyle(current, today) {
const style = {};
if (current.date() === 1) {
style.border = '1px solid #1890ff';
style.borderRadius = '50%';
}
return (
<div className="ant-calendar-date" style={style}>
{current.date()}
</div>
);
}}
/>
<RangePicker
dateRender={(current) => {
const style = {};
if (current.date() === 1) {
style.border = '1px solid #1890ff';
style.borderRadius = '50%';
return style
}
return (
<div className="ant-calendar-date" style={style}>
{current.date()}
</div>
);
}}
/>
</div>
, mountNode);
````
}
}
</script>
```

View File

@ -1,80 +1,78 @@
---
order: 6
title:
zh-CN: 不可选择日期和时间
en-US: Disabled Date & Time
---
## zh-CN
<cn>
#### 不可选择日期和时间
可用 `disabledDate``disabledTime` 分别禁止选择部分日期和时间,其中 `disabledTime` 需要和 `showTime` 一起使用。
</cn>
## en-US
<us>
#### Disabled Date & Time
Disabled part of dates and time by `disabledDate` and `disabledTime` respectively, and `disabledTime` only works with `showTime`.
</us>
````jsx
```html
<template>
<div>
<a-date-picker
format="YYYY-MM-DD HH:mm:ss"
:disabledDate="disabledDate"
:disabledTime="disabledDateTime"
:showTime="{ defaultValue: moment('00:00:00', 'HH:mm:ss') }"
/>
<br />
<a-month-picker :disabledDate="disabledDate" placeholder="Select month" />
<br />
<a-range-picker
:disabledDate="disabledDate"
:disabledTime="disabledRangeTime"
:showTime="{
hideDisabledOptions: true,
defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('11:59:59', 'HH:mm:ss')]
}"
format="YYYY-MM-DD HH:mm:ss"
/>
</div>
</template>
<script>
import moment from 'moment';
import { DatePicker } from 'antd';
const { MonthPicker, RangePicker } = DatePicker;
function range(start, end) {
export default {
methods: {
moment,
range(start, end) {
const result = [];
for (let i = start; i < end; i++) {
result.push(i);
}
return result;
}
},
function disabledDate(current) {
disabledDate(current) {
// Can not select days before today and today
return current && current < moment().endOf('day');
}
},
function disabledDateTime() {
disabledDateTime() {
return {
disabledHours: () => range(0, 24).splice(4, 20),
disabledMinutes: () => range(30, 60),
disabledHours: () => this.range(0, 24).splice(4, 20),
disabledMinutes: () => this.range(30, 60),
disabledSeconds: () => [55, 56],
};
}
},
function disabledRangeTime(_, type) {
disabledRangeTime(_, type) {
if (type === 'start') {
return {
disabledHours: () => range(0, 60).splice(4, 20),
disabledMinutes: () => range(30, 60),
disabledHours: () => this.range(0, 60).splice(4, 20),
disabledMinutes: () => this.range(30, 60),
disabledSeconds: () => [55, 56],
};
}
return {
disabledHours: () => range(0, 60).splice(20, 4),
disabledMinutes: () => range(0, 31),
disabledHours: () => this.range(0, 60).splice(20, 4),
disabledMinutes: () => this.range(0, 31),
disabledSeconds: () => [55, 56],
};
},
}
ReactDOM.render(
<div>
<DatePicker
format="YYYY-MM-DD HH:mm:ss"
disabledDate={disabledDate}
disabledTime={disabledDateTime}
showTime={{ defaultValue: moment('00:00:00', 'HH:mm:ss') }}
/>
<br />
<MonthPicker disabledDate={disabledDate} placeholder="Select month" />
<br />
<RangePicker
disabledDate={disabledDate}
disabledTime={disabledRangeTime}
showTime={{
hideDisabledOptions: true,
defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('11:59:59', 'HH:mm:ss')],
}}
format="YYYY-MM-DD HH:mm:ss"
/>
</div>,
mountNode
);
````
}
</script>
```

View File

@ -6,9 +6,9 @@ import RangePicker from './RangePicker'
import WeekPicker from './WeekPicker'
import { DatePickerProps, MonthPickerProps, WeexPickerProps, RangePickerProps } from './interface'
const DatePicker = wrapPicker(createPicker(VcCalendar), DatePickerProps())
const DatePicker = wrapPicker(createPicker(VcCalendar, DatePickerProps()), DatePickerProps())
const MonthPicker = wrapPicker(createPicker(MonthCalendar), MonthPickerProps(), 'YYYY-MM')
const MonthPicker = wrapPicker(createPicker(MonthCalendar, MonthPickerProps()), MonthPickerProps(), 'YYYY-MM')
Object.assign(DatePicker, {
RangePicker: wrapPicker(RangePicker, RangePickerProps()),

View File

@ -5,25 +5,31 @@ import PropTypes from '../_util/vue-types'
export const MomentType = {
type: Object,
validator: function (value) {
return moment.isMoment(value)
return value === undefined || moment.isMoment(value)
},
}
export const PickerProps = () => ({
transitionName: PropTypes.string,
prefixCls: PropTypes.string,
inputPrefixCls: PropTypes.string,
format: PropTypes.string,
disabled: PropTypes.boolean,
allowClear: PropTypes.boolean,
disabled: PropTypes.bool,
allowClear: PropTypes.bool,
popupStyle: PropTypes.object,
locale: PropTypes.any,
localeCode: PropTypes.string,
size: PropTypes.oneOf(['large', 'small', 'default']),
getCalendarContainer: PropTypes.func,
open: PropTypes.boolean,
// onOpenChange: PropTypes.(status: boolean) => void,
open: PropTypes.bool,
// onOpenChange: PropTypes.(status: bool) => void,
disabledDate: PropTypes.func,
renderExtraFooter: PropTypes.any,
showToday: PropTypes.bool,
dateRender: PropTypes.any, // (current: moment.Moment, today: moment.Moment) => React.ReactNode,
pickerClass: PropTypes.string,
pickerInputClass: PropTypes.string,
timePicker: PropTypes.any,
})
export const SinglePickerProps = () => ({
@ -36,10 +42,9 @@ export const SinglePickerProps = () => ({
export const DatePickerProps = () => ({
...PickerProps(), ...SinglePickerProps(),
showTime: PropTypes.oneOfType([PropTypes.shape(TimePickerProps()).loose, PropTypes.bool]),
showToday: PropTypes.bool,
open: PropTypes.bool,
disabledTime: PropTypes.func,
// onOpenChange?: (status: boolean) => void;
// onOpenChange?: (status: bool) => void;
// onOk?: (selectedTime: moment.Moment) => void;
placeholder: PropTypes.string,
})
@ -47,9 +52,10 @@ export const DatePickerProps = () => ({
export const MonthPickerProps = () => ({
...PickerProps(), ...SinglePickerProps(),
placeholder: PropTypes.string,
monthCellContentRender: PropTypes.func,
})
export const RangePickerValue = PropTypes.arrayOf(PropTypes.oneOfType([undefined, MomentType]))
export const RangePickerValue = PropTypes.arrayOf(MomentType)
export const RangePickerPresetRange = PropTypes.oneOfType([RangePickerValue, PropTypes.func])
export const RangePickerProps = () => ({
@ -62,9 +68,10 @@ export const RangePickerProps = () => ({
// onOk?: (selectedTime: moment.Moment) => void;
showTime: PropTypes.oneOfType([PropTypes.shape(TimePickerProps()).loose, PropTypes.bool]),
ranges: PropTypes.objectOf(String),
placeholder: PropTypes.oneOfType(String),
mode: PropTypes.oneOfType([PropTypes.string, PropTypes.oneOfType(String)]),
placeholder: PropTypes.arrayOf(String),
mode: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(String)]),
disabledTime: PropTypes.func,
showToday: PropTypes.bool,
// onPanelChange?: (value?: RangePickerValue, mode?: string | string[]) => void;
})

View File

@ -1,10 +1,10 @@
import TimePickerPanel from '../vc-time-picker/src/Panel'
import TimePickerPanel from '../vc-time-picker/Panel'
import classNames from 'classnames'
import LocaleReceiver from '../locale-provider/LocaleReceiver'
import { generateShowHourMinuteSecond } from '../time-picker'
import enUS from './locale/en_US'
import { getOptionProps } from '../_util/props-util'
import { getOptionProps, initDefaultProps } from '../_util/props-util'
function getColumns ({ showHour, showMinute, showSecond, use12Hours }) {
let column = 0
@ -25,23 +25,14 @@ function getColumns ({ showHour, showMinute, showSecond, use12Hours }) {
export default function wrapPicker (Picker, props, defaultFormat) {
return {
props: {
},
// static defaultProps = {
// format: defaultFormat || 'YYYY-MM-DD',
// transitionName: 'slide-up',
// popupStyle: {},
// onChange() {
// },
// onOk() {
// },
// onOpenChange() {
// },
// locale: {},
// prefixCls: 'ant-calendar',
// inputPrefixCls: 'ant-input',
// };
props: initDefaultProps(props, {
format: defaultFormat || 'YYYY-MM-DD',
transitionName: 'slide-up',
popupStyle: {},
locale: {},
prefixCls: 'ant-calendar',
inputPrefixCls: 'ant-input',
}),
mounted () {
const { autoFocus, disabled } = this
@ -135,7 +126,7 @@ export default function wrapPicker (Picker, props, defaultFormat) {
blur: this.handleBlur,
},
ref: 'picker',
scopedSlots: this.$scopedSlots || {},
}
return (
<Picker

View File

@ -104,3 +104,7 @@ const { Step } = Steps
export { Steps, Step }
export { default as Calendar } from './calendar'
import DatePicker from './date-picker'
const { MonthPicker, RangePicker, WeekPicker } = DatePicker
export { DatePicker, MonthPicker, RangePicker, WeekPicker }

View File

@ -33,3 +33,4 @@ import './time-picker/style'
import './steps/style'
import './breadcrumb/style'
import './calendar/style'
import './date-picker/style'

View File

@ -19,11 +19,18 @@ export function generateShowHourMinuteSecond (format) {
showSecond: format.indexOf('s') > -1,
}
}
function isMoment (value) {
if (Array.isArray(value)) {
return value.length === 0 || !!value.find((val) => val === undefined || moment.isMoment(val))
} else {
return value === undefined || moment.isMoment(value)
}
}
const MomentType = PropTypes.custom(isMoment)
export const TimePickerProps = () => ({
size: PropTypes.oneOf(['large', 'default', 'small']),
value: PropTypes.object,
defaultValue: PropTypes.object,
value: MomentType,
defaultValue: MomentType,
open: PropTypes.bool,
format: PropTypes.string,
disabled: PropTypes.bool,

View File

@ -4,6 +4,7 @@ import BaseMixin from '@/components/_util/BaseMixin'
import { getOptionProps, hasProp } from '@/components/_util/props-util'
import { cloneElement } from '@/components/_util/vnode'
import KeyCode from '@/components/_util/KeyCode'
import * as moment from 'moment'
import DateTable from './date/DateTable'
import CalendarHeader from './calendar/CalendarHeader'
import CalendarFooter from './calendar/CalendarFooter'
@ -46,15 +47,24 @@ function goDay (direction) {
return goTime.call(this, direction, 'days')
}
function isMoment (value) {
if (Array.isArray(value)) {
return value.length === 0 || !!value.find((val) => val === undefined || moment.isMoment(val))
} else {
return value === undefined || moment.isMoment(value)
}
}
const MomentType = PropTypes.custom(isMoment)
const Calendar = {
props: {
locale: PropTypes.object.def(enUs),
format: PropTypes.string,
visible: PropTypes.bool.def(true),
prefixCls: PropTypes.string.def('rc-calendar'),
// prefixCls: PropTypes.string,
defaultValue: PropTypes.object,
value: PropTypes.object,
selectedValue: PropTypes.object,
defaultValue: MomentType,
value: MomentType,
selectedValue: MomentType,
mode: PropTypes.oneOf(['time', 'date', 'month', 'year', 'decade']),
// locale: PropTypes.object,
showDateInput: PropTypes.bool.def(true),
@ -73,6 +83,7 @@ const Calendar = {
disabledTime: PropTypes.any,
renderFooter: PropTypes.func.def(() => null),
renderSidebar: PropTypes.func.def(() => null),
dateRender: PropTypes.func,
},
mixins: [BaseMixin, CommonMixin, CalendarMixin],
@ -219,7 +230,6 @@ const Calendar = {
let timePickerEle = null
if (timePicker && showTimePicker) {
console.log(timePicker)
const timePickerOriginProps = getOptionProps(timePicker)
const timePickerProps = {
props: {
@ -239,7 +249,6 @@ const Calendar = {
if (timePickerOriginProps.defaultValue !== undefined) {
timePickerProps.props.defaultOpenValue = timePickerOriginProps.defaultValue
}
console.log(timePickerProps)
timePickerEle = cloneElement(timePicker, timePickerProps)
}

View File

@ -11,6 +11,7 @@ import enUs from './locale/en_US'
const FullCalendar = {
props: {
locale: PropTypes.object.def(enUs),
format: PropTypes.string,
visible: PropTypes.bool.def(true),
prefixCls: PropTypes.string.def('rc-calendar'),
defaultType: PropTypes.string.def('date'),

View File

@ -10,6 +10,7 @@ import enUs from './locale/en_US'
const MonthCalendar = {
props: {
locale: PropTypes.object.def(enUs),
format: PropTypes.string,
visible: PropTypes.bool.def(true),
prefixCls: PropTypes.string.def('rc-calendar'),
monthCellRender: PropTypes.func,
@ -80,8 +81,11 @@ const MonthCalendar = {
},
render () {
const { mode, sValue: value, $props: props } = this
const { prefixCls, locale, disabledDate, monthCellRender, monthCellContentRender, renderFooter } = props
const { mode, sValue: value, $props: props, $scopedSlots } = this
const { prefixCls, locale, disabledDate } = props
const monthCellRender = this.monthCellRender || $scopedSlots.monthCellRender
const monthCellContentRender = this.monthCellContentRender || $scopedSlots.monthCellContentRender
const renderFooter = this.renderFooter || $scopedSlots.renderFooter
const children = (
<div class={`${prefixCls}-month-calendar-content`}>
<div class={`${prefixCls}-month-header-wrap`}>

View File

@ -7,12 +7,22 @@ import createChainedFunction from '@/components/_util/createChainedFunction'
import KeyCode from '@/components/_util/KeyCode'
import placements from './picker/placements'
import Trigger from '@/components/trigger'
import moment from 'moment'
import { setTimeout } from 'timers'
function isMoment (value) {
if (Array.isArray(value)) {
return value.length === 0 || !!value.find((val) => val === undefined || moment.isMoment(val))
} else {
return value === undefined || moment.isMoment(value)
}
}
const MomentType = PropTypes.custom(isMoment)
const Picker = {
props: {
animation: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
disabled: PropTypes.bool,
transitionName: PropTypes.string,
format: PropTypes.string,
// onChange: PropTypes.func,
// onOpenChange: PropTypes.func,
children: PropTypes.func,
@ -23,12 +33,12 @@ const Picker = {
prefixCls: PropTypes.string.def('rc-calendar-picker'),
placement: PropTypes.any.def('bottomLeft'),
value: PropTypes.oneOfType([
PropTypes.object,
PropTypes.array,
MomentType,
PropTypes.arrayOf(MomentType),
]),
defaultValue: PropTypes.oneOfType([
PropTypes.object,
PropTypes.array,
MomentType,
PropTypes.arrayOf(MomentType),
]),
align: PropTypes.object.def({}),
},
@ -136,7 +146,6 @@ const Picker = {
select: createChainedFunction(calendarEvents.select, this.onCalendarSelect),
clear: createChainedFunction(calendarEvents.clear, this.onCalendarClear),
},
}
return cloneElement(props.calendar, extraProps)
@ -168,8 +177,8 @@ const Picker = {
},
focusCalendar () {
if (this.sOpen && !!this.$refs.calendarInstance) {
this.$refs.calendarInstance.focus()
if (this.sOpen && this.calendarInstance && this.calendarInstance.context) {
this.calendarInstance.context.focus()
}
},
},
@ -191,6 +200,10 @@ const Picker = {
value: sValue,
open: sOpen,
}
if (this.sOpen || !this.calendarInstance) {
this.calendarInstance = this.getCalendarElement()
}
return (<Trigger
popupAlign={align}
builtinPlacements={placements}
@ -207,7 +220,7 @@ const Picker = {
popupClassName={dropdownClassName}
>
<template slot='popup'>
{this.getCalendarElement()}
{this.calendarInstance}
</template>
{cloneElement(children(childrenState, props), { on: { keydown: this.onKeyDown }})}
</Trigger>)

View File

@ -102,6 +102,7 @@ const RangeCalendar = {
disabledTime: PropTypes.func.def(noop),
renderFooter: PropTypes.func.def(() => null),
renderSidebar: PropTypes.func.def(() => null),
dateRender: PropTypes.func,
},
mixins: [BaseMixin, CommonMixin],
@ -123,7 +124,7 @@ const RangeCalendar = {
watch: {
value (val) {
const newState = {}
newState.sValue = normalizeAnchor(val, 0)
newState.sValue = normalizeAnchor(this.$props, 0)
this.setState(newState)
},
hoverValue (val) {
@ -258,25 +259,25 @@ const RangeCalendar = {
onStartPanelChange (value, mode) {
const { sMode, sValue } = this
const newMode = [mode, sMode[1]]
const newValue = [value || sValue[0], sValue[1]]
this.__emit('panelChange', newValue, newMode)
if (!hasProp(this, 'mode')) {
this.setState({
sMode: newMode,
})
}
const newValue = [value || sValue[0], sValue[1]]
this.__emit('panelChange', newValue, newMode)
},
onEndPanelChange (value, mode) {
const { sMode, sValue } = this
const newMode = [sMode[0], mode]
const newValue = [sValue[0], value || sValue[1]]
this.__emit('panelChange', newValue, newMode)
if (!hasProp(this, 'mode')) {
this.setState({
sMode: newMode,
})
}
const newValue = [sValue[0], value || sValue[1]]
this.__emit('panelChange', newValue, newMode)
},
getStartValue () {
@ -378,20 +379,13 @@ const RangeCalendar = {
}
}
}
if (!hasProp(this, 'selectedValue')) {
this.setState({
sSelectedValue: selectedValue,
})
}
//
if (!this.sSelectedValue[0] || !this.sSelectedValue[1]) {
const startValue = selectedValue[0] || moment()
const endValue = selectedValue[1] || startValue.clone().add(1, 'months')
this.setState({
sSelectedValue: selectedValue,
sValue: getValueFromSelectedValue([startValue, endValue]),
sValue: selectedValue && selectedValue.length === 2 ? getValueFromSelectedValue([startValue, endValue]) : this.sValue,
})
}
@ -408,6 +402,11 @@ const RangeCalendar = {
this.fireHoverValueChange([])
this.__emit('select', selectedValue)
}
if (!hasProp(this, 'selectedValue')) {
this.setState({
sSelectedValue: selectedValue,
})
}
},
fireValueChange (value) {
@ -606,7 +605,7 @@ const RangeCalendar = {
return (
<div
ref={this.saveRoot}
ref='rootInstance'
class={className}
tabIndex='0'
>

View File

@ -35,6 +35,8 @@ const CalendarHeader = {
enableNext: PropTypes.any.def(1),
disabledMonth: PropTypes.func,
mode: PropTypes.any,
monthCellRender: PropTypes.func,
monthCellContentRender: PropTypes.func,
},
data () {
this.nextMonth = goMonth.bind(this, 1)

View File

@ -17,13 +17,19 @@ function getNowByCurrentStateValue (value) {
}
return ret
}
function isMoment (value) {
if (Array.isArray(value)) {
return value.length === 0 || !!value.find((val) => val === undefined || moment.isMoment(val))
} else {
return value === undefined || moment.isMoment(value)
}
}
const MomentType = PropTypes.custom(isMoment)
const CalendarMixin = {
mixins: [BaseMixin],
props: {
value: PropTypes.object,
defaultValue: PropTypes.object,
// onKeyDown: PropTypes.func,
value: MomentType,
defaultValue: MomentType,
},
data () {
@ -65,7 +71,6 @@ const CalendarMixin = {
// [props.className]: !!props.className,
[newProps.class]: !!newProps.class,
}
return (
<div
ref='rootInstance'

View File

@ -25,10 +25,12 @@ const CalendarPart = {
disabledDate: PropTypes.any,
timePicker: PropTypes.any,
disabledTime: PropTypes.any,
mode: PropTypes.any,
// onInputSelect: PropTypes.func,
timePickerDisabledTime: PropTypes.object,
enableNext: PropTypes.any,
enablePrev: PropTypes.any,
dateRender: PropTypes.func,
},
render () {
const { $props: props, $listeners = {}} = this
@ -62,9 +64,10 @@ const CalendarPart = {
showTimePicker,
}
const index = direction === 'left' ? 0 : 1
let timePickerEle = null
if (shouldShowTimePicker) {
const timePickerProps = getOptionProps(timePicker)
const timePickerEle = shouldShowTimePicker &&
cloneElement(timePicker, {
timePickerEle = cloneElement(timePicker, {
props: {
showHour: true,
showMinute: true,
@ -80,6 +83,7 @@ const CalendarPart = {
},
})
}
const dateInputElement = showDateInput &&
<DateInput

View File

@ -28,8 +28,8 @@ const Panel = {
return moment()
},
},
value: PropTypes.object,
defaultValue: PropTypes.object,
value: PropTypes.any,
defaultValue: PropTypes.any,
placeholder: PropTypes.string,
format: PropTypes.string,
inputReadOnly: PropTypes.bool.def(false),

View File

@ -3,7 +3,7 @@ const AsyncComp = () => {
const hashs = window.location.hash.split('/')
const d = hashs[hashs.length - 1]
return {
component: import(`../components/calendar/demo/${d}`),
component: import(`../components/date-picker/demo/${d}`),
}
}
export default [