| disabled | Boolean | false | whether picker is disabled |
| open | Boolean | false | current open state of picker. controlled prop |
| defaultValue | GregorianCalendar | null | default initial value |
-| value | GregorianCalendar | null | current value |
+| value | GregorianCalendar | null | current value |
+| gregorianCalendarLocale | GregorianCalendar locale object | null | if value and defaultValue not set, you should set this to your locale |
| placeholder | String | '' | time input's placeholder |
-| formatter | GregorianCalendarFormatter | HH:mm:ss or HH:mm or mm:ss | |
+| showHour | Boolean | whether show hour | |
+| showSecond | Boolean | whether show second | |
+| formatter | String|GregorianCalendarFormatter | | |
| hourOptions | Array<String> | hour options | |
| minuteOptions | Array<String> | minute options | |
| secondOptions | Array<String> | second options | |
| onChange | Function | null | called when select a different value |
-| onOpen | Function | null | called when open picker |
-| onClose | Function | null | called when close picker |
-| inputClassName | String | '' | |
| placement | String | bottomLeft | one of ['left','right','top','bottom', 'topLeft', 'topRight', 'bottomLeft', 'bottomRight'] |
| transitionName | String | '' | |
@prefixClass: rc-time-picker;
.@{prefixClass} {
- display: inline;
+ display: inline-block;
box-sizing: border-box;
* {
box-sizing: border-box;
}
}
-@font-face {
- font-family: 'anticon';
- src: url('//at.alicdn.com/t/font_1434092639_4910953.eot');
- /* IE9*/
- src: url('//at.alicdn.com/t/font_1434092639_4910953.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('//at.alicdn.com/t/font_1434092639_4910953.woff') format('woff'), /* chrome、firefox */ url('//at.alicdn.com/t/font_1434092639_4910953.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/ url('//at.alicdn.com/t/font_1434092639_4910953.svg#iconfont') format('svg');
- /* iOS 4.1- */
-}
-
@import "./index/Picker";
@import "./index/Panel";
@import "./index/Header";
-@import "./index/Combobox";
@import "./index/Select";
+++ /dev/null
-.@{prefixClass} {
- &-combobox {
- }
-}
-.@{prefixClass} {
+.@{prefixClass}-panel {
&-input {
margin: 0;
padding: 0;
- border: 0;
width: 100%;
cursor: auto;
line-height: 1.5;
color: #666;
}
}
-
-.narrow .@{prefixClass}-input-wrap {
- max-width: 111px;
-}
-.@{prefixClass}-panel-inner {
- display: inline-block;
- position: relative;
- outline: none;
- border: 1px solid #ccc;
- list-style: none;
- font-size: 12px;
- text-align: left;
- background-color: #fff;
- border-radius: 3px;
- box-shadow: 0 1px 5px #ccc;
- background-clip: padding-box;
- border: 1px solid #ccc;
- line-height: 1.5;
+.@{prefixClass}-panel {
+ z-index: 1070;
+ width: 170px;
+ position: absolute;
+ box-sizing: border-box;
+
+ * {
+ box-sizing: border-box;
+ }
+
+ &-inner {
+ display: inline-block;
+ position: relative;
+ outline: none;
+ list-style: none;
+ font-size: 12px;
+ text-align: left;
+ background-color: #fff;
+ border-radius: 3px;
+ box-shadow: 0 1px 5px #ccc;
+ background-clip: padding-box;
+ border: 1px solid #ccc;
+ line-height: 1.5;
+ }
}
-.@{prefixClass}-panel {
- z-index: 1070;
- position: absolute;
-
- &.slide-up-enter.slide-up-enter-active&-placement-topLeft,
- &.slide-up-enter.slide-up-enter-active&-placement-topRight,
- &.slide-up-appear.slide-up-appear-active&-placement-topLeft,
- &.slide-up-appear.slide-up-appear-active&-placement-topRight {
- animation-name: antSlideDownIn;
- }
-
- &.slide-up-enter.slide-up-enter-active&-placement-bottomLeft,
- &.slide-up-enter.slide-up-enter-active&-placement-bottomRight,
- &.slide-up-appear.slide-up-appear-active&-placement-bottomLeft,
- &.slide-up-appear.slide-up-appear-active&-placement-bottomRight {
- animation-name: antSlideUpIn;
- }
-
- &.slide-up-leave.slide-up-leave-active&-placement-topLeft,
- &.slide-up-leave.slide-up-leave-active&-placement-topRight {
- animation-name: antSlideDownOut;
- }
-
- &.slide-up-leave.slide-up-leave-active&-placement-bottomLeft,
- &.slide-up-leave.slide-up-leave-active&-placement-bottomRight {
- animation-name: antSlideUpOut;
+.@{prefixClass} {
+ &-input {
+ width: 100%;
+ position: relative;
+ display: inline-block;
+ padding: 4px 7px;
+ height: 28px;
+ cursor: text;
+ font-size: 12px;
+ line-height: 1.5;
+ color: #666;
+ background-color: #fff;
+ background-image: none;
+ border: 1px solid #d9d9d9;
+ border-radius: 6px;
+ transition: border .2s cubic-bezier(0.645, 0.045, 0.355, 1), background .2s cubic-bezier(0.645, 0.045, 0.355, 1), box-shadow .2s cubic-bezier(0.645, 0.045, 0.355, 1);
}
}
-.@{prefixClass}-select {
+.@{prefixClass}-panel-select {
float: left;
overflow-y:auto;
font-size: 12px;
cursor: pointer;
user-select: none;
- &.selected {
- background: #edfaff;
- color: #2db7f5;
- }
-
&:hover {
background: #edfaff;
}
}
+
+ &-option-selected {
+ background: #edfaff;
+ color: #2db7f5;
+ }
}
import TimePicker from 'rc-time-picker';
import TimePickerLocale from 'rc-time-picker/src/locale/zh_CN';
-const formatter = new DateTimeFormat('HH:mm:ss');
+var showSecond = true;
+var str = showSecond ? 'HH:mm:ss' : 'HH:mm';
+
+const formatter = new DateTimeFormat(str);
const now = new GregorianCalendar(zhCn);
now.setTime(Date.now());
}
ReactDom.render(
- <TimePicker formatter={formatter} locale={TimePickerLocale} defaultValue={now} onChange={onChange}/>,
+ <TimePicker formatter={formatter} locale={TimePickerLocale}
+ showSecond={showSecond}
+ defaultValue={now}
+ onChange={onChange}/>,
document.getElementById('__react-content')
);
+
+
+console.log(zhCn);
\ No newline at end of file
{
"name": "rc-time-picker",
- "version": "0.7.1",
+ "version": "1.0.0-alpha1",
"description": "React TimePicker",
"keywords": [
"react",
"lint"
],
"dependencies": {
- "classnames": "~2.2.0",
+ "classnames": "2.x",
"gregorian-calendar": "4.x",
"gregorian-calendar-format": "4.x",
- "rc-trigger": "1.x",
- "rc-util": "2.x"
+ "rc-trigger": "1.x"
}
}
import React, {PropTypes} from 'react';
-import ReactDOM from 'react-dom';
import Trigger from 'rc-trigger';
-import {createChainedFunction} from 'rc-util';
import Panel from './module/Panel';
import placements from './util/placements';
import CommonMixin from './mixin/CommonMixin';
+import {getFormatter} from './util/index';
+import defaultGregorianCalendarLocale from 'gregorian-calendar/lib/locale/en_US';
function noop() {
}
const Picker = React.createClass({
propTypes: {
prefixCls: PropTypes.string,
- inputClassName: PropTypes.string,
locale: PropTypes.object,
value: PropTypes.object,
- children: PropTypes.func,
disabled: PropTypes.bool,
+ allowEmpty: PropTypes.bool,
defaultValue: PropTypes.object,
open: PropTypes.bool,
+ defaultOpen: PropTypes.bool,
align: PropTypes.object,
placement: PropTypes.any,
transitionName: PropTypes.string,
+ getPopupContainer: PropTypes.func,
+ gregorianCalendarLocale: PropTypes.object,
placeholder: PropTypes.string,
- formatter: PropTypes.object,
+ formatter: PropTypes.any,
+ showHour: PropTypes.bool,
+ style: PropTypes.object,
+ showSecond: PropTypes.bool,
hourOptions: PropTypes.array,
minuteOptions: PropTypes.array,
secondOptions: PropTypes.array,
getDefaultProps() {
return {
- open: false,
+ defaultOpen: false,
+ style: {},
+ gregorianCalendarLocale: defaultGregorianCalendarLocale,
align: {},
+ allowEmpty: true,
+ showHour: true,
+ showSecond: true,
placement: 'bottomLeft',
onChange: noop,
onOpen: noop,
getInitialState() {
this.savePanelRef = refFn.bind(this, 'panelInstance');
- const { open, defaultValue, value } = this.props;
+ const { defaultOpen, defaultValue, open = defaultOpen, value = defaultValue } = this.props;
return {
- open: open,
- value: value || defaultValue,
+ open,
+ value,
};
},
},
onVisibleChange(open) {
- this.setOpen(open, () => {
- if (open) {
- ReactDOM.findDOMNode(this.refs.picker).blur();
- ReactDOM.findDOMNode(this.panelInstance).focus();
- }
- });
+ this.setOpen(open);
+ },
+
+ onEsc() {
+ this.setOpen(false);
+ this.refs.picker.focus();
+ },
+
+ onKeyDown(e) {
+ if (e.keyCode === 40) {
+ this.setOpen(true);
+ }
},
setValue(value) {
this.props.onChange(value);
},
- getPanel() {
- const { prefixCls, defaultValue, locale, formatter, placeholder, hourOptions, minuteOptions, secondOptions } = this.props;
+ getFormatter() {
+ const formatter = this.props.formatter;
+ const locale = this.props.locale;
+ if (formatter) {
+ if (formatter === this.lastFormatter) {
+ return this.normalFormatter;
+ }
+ this.normalFormatter = getFormatter(formatter, locale);
+ this.lastFormatter = formatter;
+ return this.normalFormatter;
+ }
+ if (!this.props.showSecond) {
+ if (!this.notShowSecondFormatter) {
+ this.notShowSecondFormatter = getFormatter('HH:mm', locale);
+ }
+ return this.notShowSecondFormatter;
+ }
+ if (!this.props.showHour) {
+ if (!this.notShowHourFormatter) {
+ this.notShowHourFormatter = getFormatter('mm:ss', locale);
+ }
+ return this.notShowHourFormatter;
+ }
+ if (!this.normalFormatter) {
+ this.normalFormatter = getFormatter('HH:mm:ss', locale);
+ }
+ return this.normalFormatter;
+ },
+
+ getPanelElement() {
+ const { prefixCls, defaultValue, locale, placeholder, hourOptions, minuteOptions, secondOptions, allowEmpty, showHour, showSecond, gregorianCalendarLocale, value } = this.props;
+ let calendarLocale;
+ if (value) {
+ calendarLocale = value.locale;
+ } else if (defaultValue) {
+ calendarLocale = defaultValue.locale;
+ } else {
+ calendarLocale = gregorianCalendarLocale;
+ }
return (
<Panel
- prefixCls={prefixCls}
+ prefixCls={`${prefixCls}-panel`}
+ ref={this.savePanelRef}
+ value={this.state.value}
+ onChange={this.onPanelChange}
+ gregorianCalendarLocale={calendarLocale}
+ onClear={this.onPanelClear}
defaultValue={defaultValue}
+ showHour={showHour}
+ onEsc={this.onEsc}
+ showSecond={showSecond}
locale={locale}
- formatter={formatter}
+ allowEmpty={allowEmpty}
+ formatter={this.getFormatter()}
placeholder={placeholder}
hourOptions={hourOptions}
minuteOptions={minuteOptions}
);
},
- getPanelElement() {
- const panel = this.getPanel();
- const extraProps = {
- ref: this.savePanelRef,
- value: this.state.value,
- onChange: createChainedFunction(panel.props.onChange, this.onPanelChange),
- onClear: createChainedFunction(panel.props.onClear, this.onPanelClear),
- };
-
- return React.cloneElement(panel, extraProps);
- },
-
setOpen(open, callback) {
const {onOpen, onClose} = this.props;
if (this.state.open !== open) {
this.setState({
- open: open,
+ open,
}, callback);
const event = {
- open: open,
+ open,
};
if (open) {
onOpen(event);
},
render() {
- const { prefixCls, placeholder, placement, align, disabled, transitionName, formatter, inputClassName } = this.props;
+ const { prefixCls, placeholder, placement, align, disabled, transitionName, style, showHour, showSecond, getPopupContainer } = this.props;
const { open, value } = this.state;
-
+ let popupClassName;
+ if (!showHour || !showSecond) {
+ popupClassName = `${prefixCls}-panel-narrow}`;
+ }
return (
<Trigger
prefixCls={`${prefixCls}-panel`}
+ popupClassName={popupClassName}
popup={this.getPanelElement()}
popupAlign={align}
builtinPlacements={placements}
popupPlacement={placement}
action={disabled ? [] : ['click']}
destroyPopupOnHide
+ getPopupContainer={getPopupContainer}
popupTransitionName={transitionName}
popupVisible={open}
onPopupVisibleChange={this.onVisibleChange}
>
- <span className={`${prefixCls}`}>
- <input className={inputClassName} ref="picker" type="text" placeholder={placeholder} readOnly
- disabled={disabled} value={value && formatter.format(value)}/>
+ <span className={`${prefixCls}`} style={style}>
+ <input className={`${prefixCls}-input`}
+ ref="picker" type="text" placeholder={placeholder}
+ readOnly
+ onKeyDown={this.onKeyDown}
+ disabled={disabled} value={value && this.getFormatter().format(value)}/>
<span className={`${prefixCls}-icon`}/>
</span>
</Trigger>
import {PropTypes} from 'react';
import enUs from '../locale/en_US';
-import {getFormatter} from '../util/index';
export default {
propTypes: {
locale: enUs,
};
},
-
- getFormatter() {
- const formatter = this.props.formatter;
- const locale = this.props.locale;
- if (formatter) {
- if (formatter === this.lastFormatter) {
- return this.normalFormatter;
- }
- this.normalFormatter = getFormatter(formatter, locale);
- this.lastFormatter = formatter;
- return this.normalFormatter;
- }
- if (!this.showSecond) {
- if (!this.notShowSecondFormatter) {
- this.notShowSecondFormatter = getFormatter('HH:mm', locale);
- }
- return this.notShowSecondFormatter;
- }
- if (!this.showHour) {
- if (!this.notShowHourFormatter) {
- this.notShowHourFormatter = getFormatter('mm:ss', locale);
- }
- return this.notShowHourFormatter;
- }
- if (!this.normalFormatter) {
- this.normalFormatter = getFormatter('HH:mm:ss', locale);
- }
- return this.normalFormatter;
- },
};
import React, {PropTypes} from 'react';
import Select from './Select';
+import GregorianCalendar from 'gregorian-calendar';
const formatOption = (option) => {
if (option < 10) {
value: PropTypes.object,
onChange: PropTypes.func,
showHour: PropTypes.bool,
+ gregorianCalendarLocale: PropTypes.object,
showSecond: PropTypes.bool,
hourOptions: PropTypes.array,
minuteOptions: PropTypes.array,
},
onItemChange(type, itemValue) {
- const { value, onChange } = this.props;
+ const { onChange } = this.props;
+ let value = this.props.value;
+ if (value) {
+ value = value.clone();
+ } else {
+ value = this.getNow().clone();
+ }
if (type === 'hour') {
value.setHourOfDay(itemValue);
} else if (type === 'minute') {
);
},
- render() {
- const { prefixCls, value } = this.props;
+ getNow() {
+ if (this.showNow) {
+ return this.showNow;
+ }
+ const value = new GregorianCalendar(this.props.gregorianCalendarLocale);
+ value.setTime(Date.now());
+ this.showNow = value;
+ return value;
+ },
+ render() {
+ const { prefixCls } = this.props;
+ const value = this.props.value || this.getNow();
return (
<div className={`${prefixCls}-combobox`}>
{this.getHourSelect(value.getHourOfDay())}
propTypes: {
formatter: PropTypes.object,
prefixCls: PropTypes.string,
- gregorianTimePickerLocale: PropTypes.object,
+ gregorianCalendarLocale: PropTypes.object,
locale: PropTypes.object,
disabledDate: PropTypes.func,
placeholder: PropTypes.string,
secondOptions: PropTypes.array,
onChange: PropTypes.func,
onClear: PropTypes.func,
- showClear: PropTypes.bool,
+ onEsc: PropTypes.func,
+ allowEmpty: PropTypes.bool,
},
getInitialState() {
};
},
+ componentDidMount() {
+ this.timer = setTimeout(() => {
+ this.refs.input.focus();
+ }, 0);
+ },
+
componentWillReceiveProps(nextProps) {
const value = nextProps.value;
this.setState({
});
},
+ componentWillUnmount() {
+ clearTimeout(this.timer);
+ },
+
onInputChange(event) {
const str = event.target.value;
this.setState({
str,
});
let value = null;
- const {formatter, gregorianTimePickerLocale, hourOptions, minuteOptions, secondOptions, onChange} = this.props;
+ const {formatter, gregorianCalendarLocale, hourOptions, minuteOptions, secondOptions, onChange, allowEmpty} = this.props;
if (str) {
const originalValue = this.props.value;
try {
value = formatter.parse(str, {
- locale: gregorianTimePickerLocale,
+ locale: gregorianCalendarLocale,
obeyCount: true,
});
} catch (ex) {
});
return;
}
- } else {
+ } else if (allowEmpty) {
onChange(null);
+ } else {
+ this.setState({
+ invalid: true,
+ });
+ return;
}
this.setState({
});
},
+ onKeyDown(e) {
+ if (e.keyCode === 27) {
+ this.props.onEsc();
+ }
+ },
+
onClear() {
this.setState({str: ''});
this.props.onClear();
},
getClearButton() {
- const { locale, prefixCls, showClear } = this.props;
- if (!showClear) {
+ const { locale, prefixCls, allowEmpty } = this.props;
+ if (!allowEmpty) {
return null;
}
- return <a className={`${prefixCls}-clear-btn`} role="button" title={locale.clear} onMouseDown={this.onClear} />;
+ return <a className={`${prefixCls}-clear-btn`} role="button" title={locale.clear} onMouseDown={this.onClear}/>;
},
getInput() {
const { prefixCls, placeholder } = this.props;
const { invalid, str } = this.state;
const invalidClass = invalid ? `${prefixCls}-input-invalid` : '';
- return <input className={`${prefixCls}-input ${invalidClass}`} value={str} placeholder={placeholder} onChange={this.onInputChange} />;
+ return (<input className={`${prefixCls}-input ${invalidClass}`}
+ ref="input"
+ onKeyDown={this.onKeyDown}
+ value={str}
+ placeholder={placeholder} onChange={this.onInputChange}/>);
},
render() {
import React, {PropTypes} from 'react';
-import classnames from 'classnames';
-import GregorianCalendar from 'gregorian-calendar';
-import zhCn from 'gregorian-calendar/lib/locale/zh_CN';
-
import CommonMixin from '../mixin/CommonMixin';
import Header from './Header';
import Combobox from './Combobox';
value: PropTypes.object,
locale: PropTypes.object,
placeholder: PropTypes.string,
+ gregorianCalendarLocale: PropTypes.object,
formatter: PropTypes.object,
hourOptions: PropTypes.array,
minuteOptions: PropTypes.array,
secondOptions: PropTypes.array,
onChange: PropTypes.func,
+ onEsc: PropTypes.func,
+ allowEmpty: PropTypes.bool,
+ showHour: PropTypes.bool,
+ showSecond: PropTypes.bool,
onClear: PropTypes.func,
},
},
getInitialState() {
- let value = this.props.value;
- if (!value) {
- value = new GregorianCalendar(zhCn);
- value.setTime(Date.now());
- }
return {
- value,
+ value: this.props.value,
};
},
- componentWillMount() {
- const formatter = this.props.formatter;
- const pattern = formatter.originalPattern;
- if (pattern === 'HH:mm') {
- this.showSecond = false;
- } else if (pattern === 'mm:ss') {
- this.showHour = false;
- }
- },
-
componentWillReceiveProps(nextProps) {
const value = nextProps.value;
if (value) {
this.props.onClear();
},
- showHour: true,
- showSecond: true,
-
render() {
- const { locale, prefixCls, placeholder, hourOptions, minuteOptions, secondOptions } = this.props;
+ const { locale, prefixCls, placeholder, hourOptions, minuteOptions, secondOptions, allowEmpty, showHour, showSecond, formatter, gregorianCalendarLocale } = this.props;
const value = this.state.value;
- const cls = classnames({ 'narrow': !this.showHour || !this.showSecond });
-
return (
- <div className={`${prefixCls}-panel-inner ${cls}`}>
+ <div className={`${prefixCls}-inner`}>
<Header
prefixCls={prefixCls}
- gregorianTimePickerLocale={value.locale}
+ gregorianCalendarLocale={gregorianCalendarLocale}
locale={locale}
value={value}
- formatter={this.getFormatter()}
+ onEsc={this.props.onEsc}
+ formatter={formatter}
placeholder={placeholder}
hourOptions={hourOptions}
minuteOptions={minuteOptions}
secondOptions={secondOptions}
onChange={this.onChange}
onClear={this.onClear}
- showClear
+ allowEmpty={allowEmpty}
/>
<Combobox
prefixCls={prefixCls}
value={value}
- formatter={this.getFormatter()}
+ gregorianCalendarLocale={gregorianCalendarLocale}
+ formatter={formatter}
onChange={this.onChange}
- showHour={this.showHour}
- showSecond={this.showSecond}
+ showHour={showHour}
+ showSecond={showSecond}
hourOptions={hourOptions}
minuteOptions={minuteOptions}
secondOptions={secondOptions}
propTypes: {
prefixCls: PropTypes.string,
options: PropTypes.array,
+ gregorianCalendarLocale: PropTypes.object,
selectedIndex: PropTypes.number,
type: PropTypes.string,
onSelect: PropTypes.func,
this.scrollToSelected(200);
},
- onSelect(event) {
- // do nothing when select selected option
- if (event.target.getAttribute('class') === 'selected') {
- return;
- }
- // change combobox selection
+ onSelect(value) {
const { onSelect, type } = this.props;
- const value = parseInt(event.target.innerHTML, 10);
onSelect(type, value);
},
getOptions() {
- const { options, selectedIndex } = this.props;
+ const { options, selectedIndex, prefixCls } = this.props;
return options.map((item, index) => {
- const cls = classnames({ selected: selectedIndex === index});
- const ref = selectedIndex === index ? 'selected' : null;
- return <li ref={ref} className={cls} key={index} onClick={this.onSelect}>{item}</li>;
+ const selected = selectedIndex === index;
+ const cls = classnames({
+ [`${prefixCls}-select-option-selected`]: selected,
+ });
+ return <li className={cls} key={index} onClick={this.onSelect.bind(this, +item)}>{item}</li>;
});
},