]> git.immae.eu Git - github/fretlink/time-picker.git/blob - src/Combobox.jsx
Fixes #75: Disabled Hours for 12 hour picker
[github/fretlink/time-picker.git] / src / Combobox.jsx
1 import React, { Component } from 'react';
2 import PropTypes from 'prop-types';
3 import Select from './Select';
4
5 const formatOption = (option, disabledOptions) => {
6 let value = `${option}`;
7 if (option < 10) {
8 value = `0${option}`;
9 }
10
11 let disabled = false;
12 if (disabledOptions && disabledOptions.indexOf(option) >= 0) {
13 disabled = true;
14 }
15
16 return {
17 value,
18 disabled,
19 };
20 };
21
22 class Combobox extends Component {
23 static propTypes = {
24 format: PropTypes.string,
25 defaultOpenValue: PropTypes.object,
26 prefixCls: PropTypes.string,
27 value: PropTypes.object,
28 onChange: PropTypes.func,
29 showHour: PropTypes.bool,
30 showMinute: PropTypes.bool,
31 showSecond: PropTypes.bool,
32 hourOptions: PropTypes.array,
33 minuteOptions: PropTypes.array,
34 secondOptions: PropTypes.array,
35 disabledHours: PropTypes.func,
36 disabledMinutes: PropTypes.func,
37 disabledSeconds: PropTypes.func,
38 onCurrentSelectPanelChange: PropTypes.func,
39 use12Hours: PropTypes.bool,
40 };
41
42 onItemChange = (type, itemValue) => {
43 const { onChange, defaultOpenValue, use12Hours } = this.props;
44 const value = (this.props.value || defaultOpenValue).clone();
45
46 if (type === 'hour') {
47 if (use12Hours) {
48 if (this.isAM()) {
49 value.hour(+itemValue % 12);
50 } else {
51 value.hour((+itemValue % 12) + 12);
52 }
53 } else {
54 value.hour(+itemValue);
55 }
56 } else if (type === 'minute') {
57 value.minute(+itemValue);
58 } else if (type === 'ampm') {
59 const ampm = itemValue.toUpperCase();
60 if (use12Hours) {
61 if (ampm === 'PM' && value.hour() < 12) {
62 value.hour((value.hour() % 12) + 12);
63 }
64
65 if (ampm === 'AM') {
66 if (value.hour() >= 12) {
67 value.hour(value.hour() - 12);
68 }
69 }
70 }
71 } else {
72 value.second(+itemValue);
73 }
74 onChange(value);
75 }
76
77 onEnterSelectPanel = (range) => {
78 this.props.onCurrentSelectPanelChange(range);
79 }
80
81 getHourSelect(hour) {
82 const { prefixCls, hourOptions, disabledHours, showHour, use12Hours } = this.props;
83 if (!showHour) {
84 return null;
85 }
86 let disabledOptions = disabledHours();
87 let hourOptionsAdj;
88 let hourAdj;
89 if (use12Hours) {
90 hourOptionsAdj = [12].concat(hourOptions.filter(h => h < 12 && h > 0));
91 hourAdj = (hour % 12) || 12;
92
93 if (!this.isAM() && Array.isArray(disabledOptions)) {
94 disabledOptions = disabledOptions.map(h => h - 12);
95 }
96 } else {
97 hourOptionsAdj = hourOptions;
98 hourAdj = hour;
99 }
100
101 return (
102 <Select
103 prefixCls={prefixCls}
104 options={hourOptionsAdj.map(option => formatOption(option, disabledOptions))}
105 selectedIndex={hourOptionsAdj.indexOf(hourAdj)}
106 type="hour"
107 onSelect={this.onItemChange}
108 onMouseEnter={this.onEnterSelectPanel.bind(this, 'hour')}
109 />
110 );
111 }
112
113 getMinuteSelect(minute) {
114 const { prefixCls, minuteOptions, disabledMinutes, defaultOpenValue, showMinute } = this.props;
115 if (!showMinute) {
116 return null;
117 }
118 const value = this.props.value || defaultOpenValue;
119 const disabledOptions = disabledMinutes(value.hour());
120
121 return (
122 <Select
123 prefixCls={prefixCls}
124 options={minuteOptions.map(option => formatOption(option, disabledOptions))}
125 selectedIndex={minuteOptions.indexOf(minute)}
126 type="minute"
127 onSelect={this.onItemChange}
128 onMouseEnter={this.onEnterSelectPanel.bind(this, 'minute')}
129 />
130 );
131 }
132
133 getSecondSelect(second) {
134 const { prefixCls, secondOptions, disabledSeconds, showSecond, defaultOpenValue } = this.props;
135 if (!showSecond) {
136 return null;
137 }
138 const value = this.props.value || defaultOpenValue;
139 const disabledOptions = disabledSeconds(value.hour(), value.minute());
140
141 return (
142 <Select
143 prefixCls={prefixCls}
144 options={secondOptions.map(option => formatOption(option, disabledOptions))}
145 selectedIndex={secondOptions.indexOf(second)}
146 type="second"
147 onSelect={this.onItemChange}
148 onMouseEnter={this.onEnterSelectPanel.bind(this, 'second')}
149 />
150 );
151 }
152
153 getAMPMSelect() {
154 const { prefixCls, use12Hours, format } = this.props;
155 if (!use12Hours) {
156 return null;
157 }
158
159 const AMPMOptions = ['am', 'pm'] // If format has A char, then we should uppercase AM/PM
160 .map(c => format.match(/\sA/) ? c.toUpperCase() : c)
161 .map(c => ({ value: c }));
162
163 const selected = this.isAM() ? 0 : 1;
164
165 return (
166 <Select
167 prefixCls={prefixCls}
168 options={AMPMOptions}
169 selectedIndex={selected}
170 type="ampm"
171 onSelect={this.onItemChange}
172 onMouseEnter={this.onEnterSelectPanel.bind(this, 'ampm')}
173 />
174 );
175 }
176
177 isAM() {
178 const value = (this.props.value || this.props.defaultOpenValue);
179 return value.hour() >= 0 && value.hour() < 12;
180 }
181
182 render() {
183 const { prefixCls, defaultOpenValue } = this.props;
184 const value = this.props.value || defaultOpenValue;
185 return (
186 <div className={`${prefixCls}-combobox`}>
187 {this.getHourSelect(value.hour())}
188 {this.getMinuteSelect(value.minute())}
189 {this.getSecondSelect(value.second())}
190 {this.getAMPMSelect(value.hour())}
191 </div>
192 );
193 }
194 }
195
196 export default Combobox;