aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authoryiminghe <yiminghe@gmail.com>2015-11-27 16:15:05 +0800
committeryiminghe <yiminghe@gmail.com>2015-11-27 16:15:05 +0800
commit8133e8cf3b37b2be764616493ade7c7a7678fce1 (patch)
tree4321352889ab62f18ff8703adac8756ddb506dc0
parent7702bb67968104a64fa85ba7e893bf2393eeb3c5 (diff)
downloadtime-picker-8133e8cf3b37b2be764616493ade7c7a7678fce1.tar.gz
time-picker-8133e8cf3b37b2be764616493ade7c7a7678fce1.tar.zst
time-picker-8133e8cf3b37b2be764616493ade7c7a7678fce1.zip
add gregorianCalendarLocale prop1.0.0-alpha1
-rw-r--r--README.md10
-rw-r--r--assets/index.less11
-rw-r--r--assets/index/Combobox.less4
-rw-r--r--assets/index/Header.less7
-rw-r--r--assets/index/Panel.less38
-rw-r--r--assets/index/Picker.less42
-rw-r--r--assets/index/Select.less12
-rw-r--r--examples/pick-time.js13
-rw-r--r--package.json7
-rw-r--r--src/TimePicker.jsx134
-rw-r--r--src/mixin/CommonMixin.js30
-rw-r--r--src/module/Combobox.jsx24
-rw-r--r--src/module/Header.jsx44
-rw-r--r--src/module/Panel.jsx49
-rw-r--r--src/module/Select.jsx19
15 files changed, 243 insertions, 201 deletions
diff --git a/README.md b/README.md
index 1c16244..d2dcc3c 100644
--- a/README.md
+++ b/README.md
@@ -31,16 +31,16 @@ API
31| disabled | Boolean | false | whether picker is disabled | 31| disabled | Boolean | false | whether picker is disabled |
32| open | Boolean | false | current open state of picker. controlled prop | 32| open | Boolean | false | current open state of picker. controlled prop |
33| defaultValue | GregorianCalendar | null | default initial value | 33| defaultValue | GregorianCalendar | null | default initial value |
34| value | GregorianCalendar | null | current value | 34| value | GregorianCalendar | null | current value |
35| gregorianCalendarLocale | GregorianCalendar locale object | null | if value and defaultValue not set, you should set this to your locale |
35| placeholder | String | '' | time input's placeholder | 36| placeholder | String | '' | time input's placeholder |
36| formatter | GregorianCalendarFormatter | HH:mm:ss or HH:mm or mm:ss | | 37| showHour | Boolean | whether show hour | |
38| showSecond | Boolean | whether show second | |
39| formatter | String|GregorianCalendarFormatter | | |
37| hourOptions | Array<String> | hour options | | 40| hourOptions | Array<String> | hour options | |
38| minuteOptions | Array<String> | minute options | | 41| minuteOptions | Array<String> | minute options | |
39| secondOptions | Array<String> | second options | | 42| secondOptions | Array<String> | second options | |
40| onChange | Function | null | called when select a different value | 43| onChange | Function | null | called when select a different value |
41| onOpen | Function | null | called when open picker |
42| onClose | Function | null | called when close picker |
43| inputClassName | String | '' | |
44| placement | String | bottomLeft | one of ['left','right','top','bottom', 'topLeft', 'topRight', 'bottomLeft', 'bottomRight'] | 44| placement | String | bottomLeft | one of ['left','right','top','bottom', 'topLeft', 'topRight', 'bottomLeft', 'bottomRight'] |
45| transitionName | String | '' | | 45| transitionName | String | '' | |
46 46
diff --git a/assets/index.less b/assets/index.less
index 36156cb..f4caf00 100644
--- a/assets/index.less
+++ b/assets/index.less
@@ -1,23 +1,14 @@
1@prefixClass: rc-time-picker; 1@prefixClass: rc-time-picker;
2 2
3.@{prefixClass} { 3.@{prefixClass} {
4 display: inline; 4 display: inline-block;
5 box-sizing: border-box; 5 box-sizing: border-box;
6 * { 6 * {
7 box-sizing: border-box; 7 box-sizing: border-box;
8 } 8 }
9} 9}
10 10
11@font-face {
12 font-family: 'anticon';
13 src: url('//at.alicdn.com/t/font_1434092639_4910953.eot');
14 /* IE9*/
15 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');
16 /* iOS 4.1- */
17}
18
19@import "./index/Picker"; 11@import "./index/Picker";
20@import "./index/Panel"; 12@import "./index/Panel";
21@import "./index/Header"; 13@import "./index/Header";
22@import "./index/Combobox";
23@import "./index/Select"; 14@import "./index/Select";
diff --git a/assets/index/Combobox.less b/assets/index/Combobox.less
deleted file mode 100644
index a796d0a..0000000
--- a/assets/index/Combobox.less
+++ /dev/null
@@ -1,4 +0,0 @@
1.@{prefixClass} {
2 &-combobox {
3 }
4}
diff --git a/assets/index/Header.less b/assets/index/Header.less
index ac3d662..7ad3d9f 100644
--- a/assets/index/Header.less
+++ b/assets/index/Header.less
@@ -1,8 +1,7 @@
1.@{prefixClass} { 1.@{prefixClass}-panel {
2 &-input { 2 &-input {
3 margin: 0; 3 margin: 0;
4 padding: 0; 4 padding: 0;
5 border: 0;
6 width: 100%; 5 width: 100%;
7 cursor: auto; 6 cursor: auto;
8 line-height: 1.5; 7 line-height: 1.5;
@@ -48,7 +47,3 @@
48 color: #666; 47 color: #666;
49 } 48 }
50} 49}
51
52.narrow .@{prefixClass}-input-wrap {
53 max-width: 111px;
54}
diff --git a/assets/index/Panel.less b/assets/index/Panel.less
index a11c4aa..be7914f 100644
--- a/assets/index/Panel.less
+++ b/assets/index/Panel.less
@@ -1,15 +1,25 @@
1.@{prefixClass}-panel-inner { 1.@{prefixClass}-panel {
2 display: inline-block; 2 z-index: 1070;
3 position: relative; 3 width: 170px;
4 outline: none; 4 position: absolute;
5 border: 1px solid #ccc; 5 box-sizing: border-box;
6 list-style: none; 6
7 font-size: 12px; 7 * {
8 text-align: left; 8 box-sizing: border-box;
9 background-color: #fff; 9 }
10 border-radius: 3px; 10
11 box-shadow: 0 1px 5px #ccc; 11 &-inner {
12 background-clip: padding-box; 12 display: inline-block;
13 border: 1px solid #ccc; 13 position: relative;
14 line-height: 1.5; 14 outline: none;
15 list-style: none;
16 font-size: 12px;
17 text-align: left;
18 background-color: #fff;
19 border-radius: 3px;
20 box-shadow: 0 1px 5px #ccc;
21 background-clip: padding-box;
22 border: 1px solid #ccc;
23 line-height: 1.5;
24 }
15} 25}
diff --git a/assets/index/Picker.less b/assets/index/Picker.less
index dc1fbbd..76bf834 100644
--- a/assets/index/Picker.less
+++ b/assets/index/Picker.less
@@ -1,28 +1,18 @@
1.@{prefixClass}-panel { 1.@{prefixClass} {
2 z-index: 1070; 2 &-input {
3 position: absolute; 3 width: 100%;
4 4 position: relative;
5 &.slide-up-enter.slide-up-enter-active&-placement-topLeft, 5 display: inline-block;
6 &.slide-up-enter.slide-up-enter-active&-placement-topRight, 6 padding: 4px 7px;
7 &.slide-up-appear.slide-up-appear-active&-placement-topLeft, 7 height: 28px;
8 &.slide-up-appear.slide-up-appear-active&-placement-topRight { 8 cursor: text;
9 animation-name: antSlideDownIn; 9 font-size: 12px;
10 } 10 line-height: 1.5;
11 11 color: #666;
12 &.slide-up-enter.slide-up-enter-active&-placement-bottomLeft, 12 background-color: #fff;
13 &.slide-up-enter.slide-up-enter-active&-placement-bottomRight, 13 background-image: none;
14 &.slide-up-appear.slide-up-appear-active&-placement-bottomLeft, 14 border: 1px solid #d9d9d9;
15 &.slide-up-appear.slide-up-appear-active&-placement-bottomRight { 15 border-radius: 6px;
16 animation-name: antSlideUpIn; 16 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);
17 }
18
19 &.slide-up-leave.slide-up-leave-active&-placement-topLeft,
20 &.slide-up-leave.slide-up-leave-active&-placement-topRight {
21 animation-name: antSlideDownOut;
22 }
23
24 &.slide-up-leave.slide-up-leave-active&-placement-bottomLeft,
25 &.slide-up-leave.slide-up-leave-active&-placement-bottomRight {
26 animation-name: antSlideUpOut;
27 } 17 }
28} 18}
diff --git a/assets/index/Select.less b/assets/index/Select.less
index 995d09e..e93e8f7 100644
--- a/assets/index/Select.less
+++ b/assets/index/Select.less
@@ -1,4 +1,4 @@
1.@{prefixClass}-select { 1.@{prefixClass}-panel-select {
2 float: left; 2 float: left;
3 overflow-y:auto; 3 overflow-y:auto;
4 font-size: 12px; 4 font-size: 12px;
@@ -38,13 +38,13 @@
38 cursor: pointer; 38 cursor: pointer;
39 user-select: none; 39 user-select: none;
40 40
41 &.selected {
42 background: #edfaff;
43 color: #2db7f5;
44 }
45
46 &:hover { 41 &:hover {
47 background: #edfaff; 42 background: #edfaff;
48 } 43 }
49 } 44 }
45
46 &-option-selected {
47 background: #edfaff;
48 color: #2db7f5;
49 }
50} 50}
diff --git a/examples/pick-time.js b/examples/pick-time.js
index 70de23d..178b622 100644
--- a/examples/pick-time.js
+++ b/examples/pick-time.js
@@ -10,7 +10,10 @@ import zhCn from 'gregorian-calendar/lib/locale/zh_CN';
10import TimePicker from 'rc-time-picker'; 10import TimePicker from 'rc-time-picker';
11import TimePickerLocale from 'rc-time-picker/src/locale/zh_CN'; 11import TimePickerLocale from 'rc-time-picker/src/locale/zh_CN';
12 12
13const formatter = new DateTimeFormat('HH:mm:ss'); 13var showSecond = true;
14var str = showSecond ? 'HH:mm:ss' : 'HH:mm';
15
16const formatter = new DateTimeFormat(str);
14 17
15const now = new GregorianCalendar(zhCn); 18const now = new GregorianCalendar(zhCn);
16now.setTime(Date.now()); 19now.setTime(Date.now());
@@ -20,6 +23,12 @@ function onChange(value) {
20} 23}
21 24
22ReactDom.render( 25ReactDom.render(
23 <TimePicker formatter={formatter} locale={TimePickerLocale} defaultValue={now} onChange={onChange}/>, 26 <TimePicker formatter={formatter} locale={TimePickerLocale}
27 showSecond={showSecond}
28 defaultValue={now}
29 onChange={onChange}/>,
24 document.getElementById('__react-content') 30 document.getElementById('__react-content')
25); 31);
32
33
34console.log(zhCn); \ No newline at end of file
diff --git a/package.json b/package.json
index 569661f..f9246c0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
1{ 1{
2 "name": "rc-time-picker", 2 "name": "rc-time-picker",
3 "version": "0.7.1", 3 "version": "1.0.0-alpha1",
4 "description": "React TimePicker", 4 "description": "React TimePicker",
5 "keywords": [ 5 "keywords": [
6 "react", 6 "react",
@@ -57,10 +57,9 @@
57 "lint" 57 "lint"
58 ], 58 ],
59 "dependencies": { 59 "dependencies": {
60 "classnames": "~2.2.0", 60 "classnames": "2.x",
61 "gregorian-calendar": "4.x", 61 "gregorian-calendar": "4.x",
62 "gregorian-calendar-format": "4.x", 62 "gregorian-calendar-format": "4.x",
63 "rc-trigger": "1.x", 63 "rc-trigger": "1.x"
64 "rc-util": "2.x"
65 } 64 }
66} 65}
diff --git a/src/TimePicker.jsx b/src/TimePicker.jsx
index e82b46f..2694cb0 100644
--- a/src/TimePicker.jsx
+++ b/src/TimePicker.jsx
@@ -1,10 +1,10 @@
1import React, {PropTypes} from 'react'; 1import React, {PropTypes} from 'react';
2import ReactDOM from 'react-dom';
3import Trigger from 'rc-trigger'; 2import Trigger from 'rc-trigger';
4import {createChainedFunction} from 'rc-util';
5import Panel from './module/Panel'; 3import Panel from './module/Panel';
6import placements from './util/placements'; 4import placements from './util/placements';
7import CommonMixin from './mixin/CommonMixin'; 5import CommonMixin from './mixin/CommonMixin';
6import {getFormatter} from './util/index';
7import defaultGregorianCalendarLocale from 'gregorian-calendar/lib/locale/en_US';
8 8
9function noop() { 9function noop() {
10} 10}
@@ -16,18 +16,23 @@ function refFn(field, component) {
16const Picker = React.createClass({ 16const Picker = React.createClass({
17 propTypes: { 17 propTypes: {
18 prefixCls: PropTypes.string, 18 prefixCls: PropTypes.string,
19 inputClassName: PropTypes.string,
20 locale: PropTypes.object, 19 locale: PropTypes.object,
21 value: PropTypes.object, 20 value: PropTypes.object,
22 children: PropTypes.func,
23 disabled: PropTypes.bool, 21 disabled: PropTypes.bool,
22 allowEmpty: PropTypes.bool,
24 defaultValue: PropTypes.object, 23 defaultValue: PropTypes.object,
25 open: PropTypes.bool, 24 open: PropTypes.bool,
25 defaultOpen: PropTypes.bool,
26 align: PropTypes.object, 26 align: PropTypes.object,
27 placement: PropTypes.any, 27 placement: PropTypes.any,
28 transitionName: PropTypes.string, 28 transitionName: PropTypes.string,
29 getPopupContainer: PropTypes.func,
30 gregorianCalendarLocale: PropTypes.object,
29 placeholder: PropTypes.string, 31 placeholder: PropTypes.string,
30 formatter: PropTypes.object, 32 formatter: PropTypes.any,
33 showHour: PropTypes.bool,
34 style: PropTypes.object,
35 showSecond: PropTypes.bool,
31 hourOptions: PropTypes.array, 36 hourOptions: PropTypes.array,
32 minuteOptions: PropTypes.array, 37 minuteOptions: PropTypes.array,
33 secondOptions: PropTypes.array, 38 secondOptions: PropTypes.array,
@@ -40,8 +45,13 @@ const Picker = React.createClass({
40 45
41 getDefaultProps() { 46 getDefaultProps() {
42 return { 47 return {
43 open: false, 48 defaultOpen: false,
49 style: {},
50 gregorianCalendarLocale: defaultGregorianCalendarLocale,
44 align: {}, 51 align: {},
52 allowEmpty: true,
53 showHour: true,
54 showSecond: true,
45 placement: 'bottomLeft', 55 placement: 'bottomLeft',
46 onChange: noop, 56 onChange: noop,
47 onOpen: noop, 57 onOpen: noop,
@@ -51,10 +61,10 @@ const Picker = React.createClass({
51 61
52 getInitialState() { 62 getInitialState() {
53 this.savePanelRef = refFn.bind(this, 'panelInstance'); 63 this.savePanelRef = refFn.bind(this, 'panelInstance');
54 const { open, defaultValue, value } = this.props; 64 const { defaultOpen, defaultValue, open = defaultOpen, value = defaultValue } = this.props;
55 return { 65 return {
56 open: open, 66 open,
57 value: value || defaultValue, 67 value,
58 }; 68 };
59 }, 69 },
60 70
@@ -80,12 +90,18 @@ const Picker = React.createClass({
80 }, 90 },
81 91
82 onVisibleChange(open) { 92 onVisibleChange(open) {
83 this.setOpen(open, () => { 93 this.setOpen(open);
84 if (open) { 94 },
85 ReactDOM.findDOMNode(this.refs.picker).blur(); 95
86 ReactDOM.findDOMNode(this.panelInstance).focus(); 96 onEsc() {
87 } 97 this.setOpen(false);
88 }); 98 this.refs.picker.focus();
99 },
100
101 onKeyDown(e) {
102 if (e.keyCode === 40) {
103 this.setOpen(true);
104 }
89 }, 105 },
90 106
91 setValue(value) { 107 setValue(value) {
@@ -97,14 +113,60 @@ const Picker = React.createClass({
97 this.props.onChange(value); 113 this.props.onChange(value);
98 }, 114 },
99 115
100 getPanel() { 116 getFormatter() {
101 const { prefixCls, defaultValue, locale, formatter, placeholder, hourOptions, minuteOptions, secondOptions } = this.props; 117 const formatter = this.props.formatter;
118 const locale = this.props.locale;
119 if (formatter) {
120 if (formatter === this.lastFormatter) {
121 return this.normalFormatter;
122 }
123 this.normalFormatter = getFormatter(formatter, locale);
124 this.lastFormatter = formatter;
125 return this.normalFormatter;
126 }
127 if (!this.props.showSecond) {
128 if (!this.notShowSecondFormatter) {
129 this.notShowSecondFormatter = getFormatter('HH:mm', locale);
130 }
131 return this.notShowSecondFormatter;
132 }
133 if (!this.props.showHour) {
134 if (!this.notShowHourFormatter) {
135 this.notShowHourFormatter = getFormatter('mm:ss', locale);
136 }
137 return this.notShowHourFormatter;
138 }
139 if (!this.normalFormatter) {
140 this.normalFormatter = getFormatter('HH:mm:ss', locale);
141 }
142 return this.normalFormatter;
143 },
144
145 getPanelElement() {
146 const { prefixCls, defaultValue, locale, placeholder, hourOptions, minuteOptions, secondOptions, allowEmpty, showHour, showSecond, gregorianCalendarLocale, value } = this.props;
147 let calendarLocale;
148 if (value) {
149 calendarLocale = value.locale;
150 } else if (defaultValue) {
151 calendarLocale = defaultValue.locale;
152 } else {
153 calendarLocale = gregorianCalendarLocale;
154 }
102 return ( 155 return (
103 <Panel 156 <Panel
104 prefixCls={prefixCls} 157 prefixCls={`${prefixCls}-panel`}
158 ref={this.savePanelRef}
159 value={this.state.value}
160 onChange={this.onPanelChange}
161 gregorianCalendarLocale={calendarLocale}
162 onClear={this.onPanelClear}
105 defaultValue={defaultValue} 163 defaultValue={defaultValue}
164 showHour={showHour}
165 onEsc={this.onEsc}
166 showSecond={showSecond}
106 locale={locale} 167 locale={locale}
107 formatter={formatter} 168 allowEmpty={allowEmpty}
169 formatter={this.getFormatter()}
108 placeholder={placeholder} 170 placeholder={placeholder}
109 hourOptions={hourOptions} 171 hourOptions={hourOptions}
110 minuteOptions={minuteOptions} 172 minuteOptions={minuteOptions}
@@ -113,26 +175,14 @@ const Picker = React.createClass({
113 ); 175 );
114 }, 176 },
115 177
116 getPanelElement() {
117 const panel = this.getPanel();
118 const extraProps = {
119 ref: this.savePanelRef,
120 value: this.state.value,
121 onChange: createChainedFunction(panel.props.onChange, this.onPanelChange),
122 onClear: createChainedFunction(panel.props.onClear, this.onPanelClear),
123 };
124
125 return React.cloneElement(panel, extraProps);
126 },
127
128 setOpen(open, callback) { 178 setOpen(open, callback) {
129 const {onOpen, onClose} = this.props; 179 const {onOpen, onClose} = this.props;
130 if (this.state.open !== open) { 180 if (this.state.open !== open) {
131 this.setState({ 181 this.setState({
132 open: open, 182 open,
133 }, callback); 183 }, callback);
134 const event = { 184 const event = {
135 open: open, 185 open,
136 }; 186 };
137 if (open) { 187 if (open) {
138 onOpen(event); 188 onOpen(event);
@@ -143,25 +193,33 @@ const Picker = React.createClass({
143 }, 193 },
144 194
145 render() { 195 render() {
146 const { prefixCls, placeholder, placement, align, disabled, transitionName, formatter, inputClassName } = this.props; 196 const { prefixCls, placeholder, placement, align, disabled, transitionName, style, showHour, showSecond, getPopupContainer } = this.props;
147 const { open, value } = this.state; 197 const { open, value } = this.state;
148 198 let popupClassName;
199 if (!showHour || !showSecond) {
200 popupClassName = `${prefixCls}-panel-narrow}`;
201 }
149 return ( 202 return (
150 <Trigger 203 <Trigger
151 prefixCls={`${prefixCls}-panel`} 204 prefixCls={`${prefixCls}-panel`}
205 popupClassName={popupClassName}
152 popup={this.getPanelElement()} 206 popup={this.getPanelElement()}
153 popupAlign={align} 207 popupAlign={align}
154 builtinPlacements={placements} 208 builtinPlacements={placements}
155 popupPlacement={placement} 209 popupPlacement={placement}
156 action={disabled ? [] : ['click']} 210 action={disabled ? [] : ['click']}
157 destroyPopupOnHide 211 destroyPopupOnHide
212 getPopupContainer={getPopupContainer}
158 popupTransitionName={transitionName} 213 popupTransitionName={transitionName}
159 popupVisible={open} 214 popupVisible={open}
160 onPopupVisibleChange={this.onVisibleChange} 215 onPopupVisibleChange={this.onVisibleChange}
161 > 216 >
162 <span className={`${prefixCls}`}> 217 <span className={`${prefixCls}`} style={style}>
163 <input className={inputClassName} ref="picker" type="text" placeholder={placeholder} readOnly 218 <input className={`${prefixCls}-input`}
164 disabled={disabled} value={value && formatter.format(value)}/> 219 ref="picker" type="text" placeholder={placeholder}
220 readOnly
221 onKeyDown={this.onKeyDown}
222 disabled={disabled} value={value && this.getFormatter().format(value)}/>
165 <span className={`${prefixCls}-icon`}/> 223 <span className={`${prefixCls}-icon`}/>
166 </span> 224 </span>
167 </Trigger> 225 </Trigger>
diff --git a/src/mixin/CommonMixin.js b/src/mixin/CommonMixin.js
index 0e8ed32..a6893b8 100644
--- a/src/mixin/CommonMixin.js
+++ b/src/mixin/CommonMixin.js
@@ -1,6 +1,5 @@
1import {PropTypes} from 'react'; 1import {PropTypes} from 'react';
2import enUs from '../locale/en_US'; 2import enUs from '../locale/en_US';
3import {getFormatter} from '../util/index';
4 3
5export default { 4export default {
6 propTypes: { 5 propTypes: {
@@ -14,33 +13,4 @@ export default {
14 locale: enUs, 13 locale: enUs,
15 }; 14 };
16 }, 15 },
17
18 getFormatter() {
19 const formatter = this.props.formatter;
20 const locale = this.props.locale;
21 if (formatter) {
22 if (formatter === this.lastFormatter) {
23 return this.normalFormatter;
24 }
25 this.normalFormatter = getFormatter(formatter, locale);
26 this.lastFormatter = formatter;
27 return this.normalFormatter;
28 }
29 if (!this.showSecond) {
30 if (!this.notShowSecondFormatter) {
31 this.notShowSecondFormatter = getFormatter('HH:mm', locale);
32 }
33 return this.notShowSecondFormatter;
34 }
35 if (!this.showHour) {
36 if (!this.notShowHourFormatter) {
37 this.notShowHourFormatter = getFormatter('mm:ss', locale);
38 }
39 return this.notShowHourFormatter;
40 }
41 if (!this.normalFormatter) {
42 this.normalFormatter = getFormatter('HH:mm:ss', locale);
43 }
44 return this.normalFormatter;
45 },
46}; 16};
diff --git a/src/module/Combobox.jsx b/src/module/Combobox.jsx
index afce675..3dfd321 100644
--- a/src/module/Combobox.jsx
+++ b/src/module/Combobox.jsx
@@ -1,5 +1,6 @@
1import React, {PropTypes} from 'react'; 1import React, {PropTypes} from 'react';
2import Select from './Select'; 2import Select from './Select';
3import GregorianCalendar from 'gregorian-calendar';
3 4
4const formatOption = (option) => { 5const formatOption = (option) => {
5 if (option < 10) { 6 if (option < 10) {
@@ -15,6 +16,7 @@ const Combobox = React.createClass({
15 value: PropTypes.object, 16 value: PropTypes.object,
16 onChange: PropTypes.func, 17 onChange: PropTypes.func,
17 showHour: PropTypes.bool, 18 showHour: PropTypes.bool,
19 gregorianCalendarLocale: PropTypes.object,
18 showSecond: PropTypes.bool, 20 showSecond: PropTypes.bool,
19 hourOptions: PropTypes.array, 21 hourOptions: PropTypes.array,
20 minuteOptions: PropTypes.array, 22 minuteOptions: PropTypes.array,
@@ -22,7 +24,13 @@ const Combobox = React.createClass({
22 }, 24 },
23 25
24 onItemChange(type, itemValue) { 26 onItemChange(type, itemValue) {
25 const { value, onChange } = this.props; 27 const { onChange } = this.props;
28 let value = this.props.value;
29 if (value) {
30 value = value.clone();
31 } else {
32 value = this.getNow().clone();
33 }
26 if (type === 'hour') { 34 if (type === 'hour') {
27 value.setHourOfDay(itemValue); 35 value.setHourOfDay(itemValue);
28 } else if (type === 'minute') { 36 } else if (type === 'minute') {
@@ -78,9 +86,19 @@ const Combobox = React.createClass({
78 ); 86 );
79 }, 87 },
80 88
81 render() { 89 getNow() {
82 const { prefixCls, value } = this.props; 90 if (this.showNow) {
91 return this.showNow;
92 }
93 const value = new GregorianCalendar(this.props.gregorianCalendarLocale);
94 value.setTime(Date.now());
95 this.showNow = value;
96 return value;
97 },
83 98
99 render() {
100 const { prefixCls } = this.props;
101 const value = this.props.value || this.getNow();
84 return ( 102 return (
85 <div className={`${prefixCls}-combobox`}> 103 <div className={`${prefixCls}-combobox`}>
86 {this.getHourSelect(value.getHourOfDay())} 104 {this.getHourSelect(value.getHourOfDay())}
diff --git a/src/module/Header.jsx b/src/module/Header.jsx
index b65fd25..962328c 100644
--- a/src/module/Header.jsx
+++ b/src/module/Header.jsx
@@ -4,7 +4,7 @@ const Header = React.createClass({
4 propTypes: { 4 propTypes: {
5 formatter: PropTypes.object, 5 formatter: PropTypes.object,
6 prefixCls: PropTypes.string, 6 prefixCls: PropTypes.string,
7 gregorianTimePickerLocale: PropTypes.object, 7 gregorianCalendarLocale: PropTypes.object,
8 locale: PropTypes.object, 8 locale: PropTypes.object,
9 disabledDate: PropTypes.func, 9 disabledDate: PropTypes.func,
10 placeholder: PropTypes.string, 10 placeholder: PropTypes.string,
@@ -14,7 +14,8 @@ const Header = React.createClass({
14 secondOptions: PropTypes.array, 14 secondOptions: PropTypes.array,
15 onChange: PropTypes.func, 15 onChange: PropTypes.func,
16 onClear: PropTypes.func, 16 onClear: PropTypes.func,
17 showClear: PropTypes.bool, 17 onEsc: PropTypes.func,
18 allowEmpty: PropTypes.bool,
18 }, 19 },
19 20
20 getInitialState() { 21 getInitialState() {
@@ -25,6 +26,12 @@ const Header = React.createClass({
25 }; 26 };
26 }, 27 },
27 28
29 componentDidMount() {
30 this.timer = setTimeout(() => {
31 this.refs.input.focus();
32 }, 0);
33 },
34
28 componentWillReceiveProps(nextProps) { 35 componentWillReceiveProps(nextProps) {
29 const value = nextProps.value; 36 const value = nextProps.value;
30 this.setState({ 37 this.setState({
@@ -33,19 +40,23 @@ const Header = React.createClass({
33 }); 40 });
34 }, 41 },
35 42
43 componentWillUnmount() {
44 clearTimeout(this.timer);
45 },
46
36 onInputChange(event) { 47 onInputChange(event) {
37 const str = event.target.value; 48 const str = event.target.value;
38 this.setState({ 49 this.setState({
39 str, 50 str,
40 }); 51 });
41 let value = null; 52 let value = null;
42 const {formatter, gregorianTimePickerLocale, hourOptions, minuteOptions, secondOptions, onChange} = this.props; 53 const {formatter, gregorianCalendarLocale, hourOptions, minuteOptions, secondOptions, onChange, allowEmpty} = this.props;
43 54
44 if (str) { 55 if (str) {
45 const originalValue = this.props.value; 56 const originalValue = this.props.value;
46 try { 57 try {
47 value = formatter.parse(str, { 58 value = formatter.parse(str, {
48 locale: gregorianTimePickerLocale, 59 locale: gregorianCalendarLocale,
49 obeyCount: true, 60 obeyCount: true,
50 }); 61 });
51 } catch (ex) { 62 } catch (ex) {
@@ -84,8 +95,13 @@ const Header = React.createClass({
84 }); 95 });
85 return; 96 return;
86 } 97 }
87 } else { 98 } else if (allowEmpty) {
88 onChange(null); 99 onChange(null);
100 } else {
101 this.setState({
102 invalid: true,
103 });
104 return;
89 } 105 }
90 106
91 this.setState({ 107 this.setState({
@@ -93,24 +109,34 @@ const Header = React.createClass({
93 }); 109 });
94 }, 110 },
95 111
112 onKeyDown(e) {
113 if (e.keyCode === 27) {
114 this.props.onEsc();
115 }
116 },
117
96 onClear() { 118 onClear() {
97 this.setState({str: ''}); 119 this.setState({str: ''});
98 this.props.onClear(); 120 this.props.onClear();
99 }, 121 },
100 122
101 getClearButton() { 123 getClearButton() {
102 const { locale, prefixCls, showClear } = this.props; 124 const { locale, prefixCls, allowEmpty } = this.props;
103 if (!showClear) { 125 if (!allowEmpty) {
104 return null; 126 return null;
105 } 127 }
106 return <a className={`${prefixCls}-clear-btn`} role="button" title={locale.clear} onMouseDown={this.onClear} />; 128 return <a className={`${prefixCls}-clear-btn`} role="button" title={locale.clear} onMouseDown={this.onClear}/>;
107 }, 129 },
108 130
109 getInput() { 131 getInput() {
110 const { prefixCls, placeholder } = this.props; 132 const { prefixCls, placeholder } = this.props;
111 const { invalid, str } = this.state; 133 const { invalid, str } = this.state;
112 const invalidClass = invalid ? `${prefixCls}-input-invalid` : ''; 134 const invalidClass = invalid ? `${prefixCls}-input-invalid` : '';
113 return <input className={`${prefixCls}-input ${invalidClass}`} value={str} placeholder={placeholder} onChange={this.onInputChange} />; 135 return (<input className={`${prefixCls}-input ${invalidClass}`}
136 ref="input"
137 onKeyDown={this.onKeyDown}
138 value={str}
139 placeholder={placeholder} onChange={this.onInputChange}/>);
114 }, 140 },
115 141
116 render() { 142 render() {
diff --git a/src/module/Panel.jsx b/src/module/Panel.jsx
index e372774..b91c6fe 100644
--- a/src/module/Panel.jsx
+++ b/src/module/Panel.jsx
@@ -1,8 +1,4 @@
1import React, {PropTypes} from 'react'; 1import React, {PropTypes} from 'react';
2import classnames from 'classnames';
3import GregorianCalendar from 'gregorian-calendar';
4import zhCn from 'gregorian-calendar/lib/locale/zh_CN';
5
6import CommonMixin from '../mixin/CommonMixin'; 2import CommonMixin from '../mixin/CommonMixin';
7import Header from './Header'; 3import Header from './Header';
8import Combobox from './Combobox'; 4import Combobox from './Combobox';
@@ -22,11 +18,16 @@ const Panel = React.createClass({
22 value: PropTypes.object, 18 value: PropTypes.object,
23 locale: PropTypes.object, 19 locale: PropTypes.object,
24 placeholder: PropTypes.string, 20 placeholder: PropTypes.string,
21 gregorianCalendarLocale: PropTypes.object,
25 formatter: PropTypes.object, 22 formatter: PropTypes.object,
26 hourOptions: PropTypes.array, 23 hourOptions: PropTypes.array,
27 minuteOptions: PropTypes.array, 24 minuteOptions: PropTypes.array,
28 secondOptions: PropTypes.array, 25 secondOptions: PropTypes.array,
29 onChange: PropTypes.func, 26 onChange: PropTypes.func,
27 onEsc: PropTypes.func,
28 allowEmpty: PropTypes.bool,
29 showHour: PropTypes.bool,
30 showSecond: PropTypes.bool,
30 onClear: PropTypes.func, 31 onClear: PropTypes.func,
31 }, 32 },
32 33
@@ -43,26 +44,11 @@ const Panel = React.createClass({
43 }, 44 },
44 45
45 getInitialState() { 46 getInitialState() {
46 let value = this.props.value;
47 if (!value) {
48 value = new GregorianCalendar(zhCn);
49 value.setTime(Date.now());
50 }
51 return { 47 return {
52 value, 48 value: this.props.value,
53 }; 49 };
54 }, 50 },
55 51
56 componentWillMount() {
57 const formatter = this.props.formatter;
58 const pattern = formatter.originalPattern;
59 if (pattern === 'HH:mm') {
60 this.showSecond = false;
61 } else if (pattern === 'mm:ss') {
62 this.showHour = false;
63 }
64 },
65
66 componentWillReceiveProps(nextProps) { 52 componentWillReceiveProps(nextProps) {
67 const value = nextProps.value; 53 const value = nextProps.value;
68 if (value) { 54 if (value) {
@@ -81,37 +67,34 @@ const Panel = React.createClass({
81 this.props.onClear(); 67 this.props.onClear();
82 }, 68 },
83 69
84 showHour: true,
85 showSecond: true,
86
87 render() { 70 render() {
88 const { locale, prefixCls, placeholder, hourOptions, minuteOptions, secondOptions } = this.props; 71 const { locale, prefixCls, placeholder, hourOptions, minuteOptions, secondOptions, allowEmpty, showHour, showSecond, formatter, gregorianCalendarLocale } = this.props;
89 const value = this.state.value; 72 const value = this.state.value;
90 const cls = classnames({ 'narrow': !this.showHour || !this.showSecond });
91
92 return ( 73 return (
93 <div className={`${prefixCls}-panel-inner ${cls}`}> 74 <div className={`${prefixCls}-inner`}>
94 <Header 75 <Header
95 prefixCls={prefixCls} 76 prefixCls={prefixCls}
96 gregorianTimePickerLocale={value.locale} 77 gregorianCalendarLocale={gregorianCalendarLocale}
97 locale={locale} 78 locale={locale}
98 value={value} 79 value={value}
99 formatter={this.getFormatter()} 80 onEsc={this.props.onEsc}
81 formatter={formatter}
100 placeholder={placeholder} 82 placeholder={placeholder}
101 hourOptions={hourOptions} 83 hourOptions={hourOptions}
102 minuteOptions={minuteOptions} 84 minuteOptions={minuteOptions}
103 secondOptions={secondOptions} 85 secondOptions={secondOptions}
104 onChange={this.onChange} 86 onChange={this.onChange}
105 onClear={this.onClear} 87 onClear={this.onClear}
106 showClear 88 allowEmpty={allowEmpty}
107 /> 89 />
108 <Combobox 90 <Combobox
109 prefixCls={prefixCls} 91 prefixCls={prefixCls}
110 value={value} 92 value={value}
111 formatter={this.getFormatter()} 93 gregorianCalendarLocale={gregorianCalendarLocale}
94 formatter={formatter}
112 onChange={this.onChange} 95 onChange={this.onChange}
113 showHour={this.showHour} 96 showHour={showHour}
114 showSecond={this.showSecond} 97 showSecond={showSecond}
115 hourOptions={hourOptions} 98 hourOptions={hourOptions}
116 minuteOptions={minuteOptions} 99 minuteOptions={minuteOptions}
117 secondOptions={secondOptions} 100 secondOptions={secondOptions}
diff --git a/src/module/Select.jsx b/src/module/Select.jsx
index 2b69623..be4c025 100644
--- a/src/module/Select.jsx
+++ b/src/module/Select.jsx
@@ -22,6 +22,7 @@ const Select = React.createClass({
22 propTypes: { 22 propTypes: {
23 prefixCls: PropTypes.string, 23 prefixCls: PropTypes.string,
24 options: PropTypes.array, 24 options: PropTypes.array,
25 gregorianCalendarLocale: PropTypes.object,
25 selectedIndex: PropTypes.number, 26 selectedIndex: PropTypes.number,
26 type: PropTypes.string, 27 type: PropTypes.string,
27 onSelect: PropTypes.func, 28 onSelect: PropTypes.func,
@@ -37,23 +38,19 @@ const Select = React.createClass({
37 this.scrollToSelected(200); 38 this.scrollToSelected(200);
38 }, 39 },
39 40
40 onSelect(event) { 41 onSelect(value) {
41 // do nothing when select selected option
42 if (event.target.getAttribute('class') === 'selected') {
43 return;
44 }
45 // change combobox selection
46 const { onSelect, type } = this.props; 42 const { onSelect, type } = this.props;
47 const value = parseInt(event.target.innerHTML, 10);
48 onSelect(type, value); 43 onSelect(type, value);
49 }, 44 },
50 45
51 getOptions() { 46 getOptions() {
52 const { options, selectedIndex } = this.props; 47 const { options, selectedIndex, prefixCls } = this.props;
53 return options.map((item, index) => { 48 return options.map((item, index) => {
54 const cls = classnames({ selected: selectedIndex === index}); 49 const selected = selectedIndex === index;
55 const ref = selectedIndex === index ? 'selected' : null; 50 const cls = classnames({
56 return <li ref={ref} className={cls} key={index} onClick={this.onSelect}>{item}</li>; 51 [`${prefixCls}-select-option-selected`]: selected,
52 });
53 return <li className={cls} key={index} onClick={this.onSelect.bind(this, +item)}>{item}</li>;
57 }); 54 });
58 }, 55 },
59 56