]> git.immae.eu Git - github/fretlink/time-picker.git/blob - src/Panel.jsx
Add a prop to configure whether `<kbd>esc</kbd>` should close the panel
[github/fretlink/time-picker.git] / src / Panel.jsx
1 import React, { Component } from 'react';
2 import PropTypes from 'prop-types';
3 import Header from './Header';
4 import Combobox from './Combobox';
5 import moment from 'moment';
6 import classNames from 'classnames';
7
8 function noop() {
9 }
10
11 function generateOptions(length, disabledOptions, hideDisabledOptions, step = 1) {
12 const arr = [];
13 for (let value = 0; value < length; value += step) {
14 if (!disabledOptions || disabledOptions.indexOf(value) < 0 || !hideDisabledOptions) {
15 arr.push(value);
16 }
17 }
18 return arr;
19 }
20
21 class Panel extends Component {
22 static propTypes = {
23 clearText: PropTypes.string,
24 prefixCls: PropTypes.string,
25 className: PropTypes.string,
26 defaultOpenValue: PropTypes.object,
27 value: PropTypes.object,
28 placeholder: PropTypes.string,
29 format: PropTypes.string,
30 inputReadOnly: PropTypes.bool,
31 disabledHours: PropTypes.func,
32 disabledMinutes: PropTypes.func,
33 disabledSeconds: PropTypes.func,
34 hideDisabledOptions: PropTypes.bool,
35 onChange: PropTypes.func,
36 onEsc: PropTypes.func,
37 allowEmpty: PropTypes.bool,
38 showHour: PropTypes.bool,
39 showMinute: PropTypes.bool,
40 showSecond: PropTypes.bool,
41 onClear: PropTypes.func,
42 use12Hours: PropTypes.bool,
43 hourStep: PropTypes.number,
44 minuteStep: PropTypes.number,
45 secondStep: PropTypes.number,
46 addon: PropTypes.func,
47 focusOnOpen: PropTypes.bool,
48 closeOnEsc: PropTypes.bool,
49 onKeyDown: PropTypes.func,
50 };
51
52 static defaultProps = {
53 prefixCls: 'rc-time-picker-panel',
54 onChange: noop,
55 onClear: noop,
56 disabledHours: noop,
57 disabledMinutes: noop,
58 disabledSeconds: noop,
59 defaultOpenValue: moment(),
60 use12Hours: false,
61 addon: noop,
62 onKeyDown: noop,
63 inputReadOnly: false,
64 closeOnEsc: true,
65 };
66
67 constructor(props) {
68 super(props);
69 this.state = {
70 value: props.value,
71 selectionRange: [],
72 };
73 }
74
75 componentWillReceiveProps(nextProps) {
76 const value = nextProps.value;
77 if (value) {
78 this.setState({
79 value,
80 });
81 }
82 }
83
84 onChange = (newValue) => {
85 this.setState({ value: newValue });
86 this.props.onChange(newValue);
87 }
88
89 onCurrentSelectPanelChange = (currentSelectPanel) => {
90 this.setState({ currentSelectPanel });
91 }
92
93 // https://github.com/ant-design/ant-design/issues/5829
94 close() {
95 this.props.onEsc();
96 }
97
98 disabledHours = () => {
99 const { use12Hours, disabledHours } = this.props;
100 let disabledOptions = disabledHours();
101 if (use12Hours && Array.isArray(disabledOptions)) {
102 if (this.isAM()) {
103 disabledOptions = disabledOptions.filter(h => h < 12).map(h => (h === 0 ? 12 : h));
104 } else {
105 disabledOptions = disabledOptions.map(h => (h === 12 ? 12 : h - 12));
106 }
107 }
108 return disabledOptions;
109 }
110
111 isAM() {
112 const value = (this.state.value || this.props.defaultOpenValue);
113 return value.hour() >= 0 && value.hour() < 12;
114 }
115
116 render() {
117 const {
118 prefixCls, className, placeholder, disabledMinutes,
119 disabledSeconds, hideDisabledOptions, allowEmpty, showHour, showMinute, showSecond,
120 format, defaultOpenValue, clearText, onEsc, addon, use12Hours, onClear,
121 focusOnOpen, onKeyDown, hourStep, minuteStep, secondStep, inputReadOnly,
122 closeOnEsc,
123 } = this.props;
124 const {
125 value, currentSelectPanel,
126 } = this.state;
127 const disabledHourOptions = this.disabledHours();
128 const disabledMinuteOptions = disabledMinutes(value ? value.hour() : null);
129 const disabledSecondOptions = disabledSeconds(value ? value.hour() : null,
130 value ? value.minute() : null);
131 const hourOptions = generateOptions(
132 24, disabledHourOptions, hideDisabledOptions, hourStep
133 );
134 const minuteOptions = generateOptions(
135 60, disabledMinuteOptions, hideDisabledOptions, minuteStep
136 );
137 const secondOptions = generateOptions(
138 60, disabledSecondOptions, hideDisabledOptions, secondStep
139 );
140
141 return (
142 <div className={classNames({ [`${prefixCls}-inner`]: true, [className]: !!className })}>
143 <Header
144 clearText={clearText}
145 prefixCls={prefixCls}
146 defaultOpenValue={defaultOpenValue}
147 value={value}
148 currentSelectPanel={currentSelectPanel}
149 onEsc={closeOnEsc ? onEsc : undefined}
150 format={format}
151 placeholder={placeholder}
152 hourOptions={hourOptions}
153 minuteOptions={minuteOptions}
154 secondOptions={secondOptions}
155 disabledHours={this.disabledHours}
156 disabledMinutes={disabledMinutes}
157 disabledSeconds={disabledSeconds}
158 onChange={this.onChange}
159 onClear={onClear}
160 allowEmpty={allowEmpty}
161 focusOnOpen={focusOnOpen}
162 onKeyDown={onKeyDown}
163 inputReadOnly={inputReadOnly}
164 />
165 <Combobox
166 prefixCls={prefixCls}
167 value={value}
168 defaultOpenValue={defaultOpenValue}
169 format={format}
170 onChange={this.onChange}
171 showHour={showHour}
172 showMinute={showMinute}
173 showSecond={showSecond}
174 hourOptions={hourOptions}
175 minuteOptions={minuteOptions}
176 secondOptions={secondOptions}
177 disabledHours={this.disabledHours}
178 disabledMinutes={disabledMinutes}
179 disabledSeconds={disabledSeconds}
180 onCurrentSelectPanelChange={this.onCurrentSelectPanelChange}
181 use12Hours={use12Hours}
182 isAM={this.isAM()}
183 />
184 {addon(this)}
185 </div>
186 );
187 }
188 }
189
190 export default Panel;