1 | "use strict";
|
2 |
|
3 | exports.__esModule = true;
|
4 | exports.default = void 0;
|
5 |
|
6 | var _classnames = _interopRequireDefault(require("classnames"));
|
7 |
|
8 | var _querySelectorAll = _interopRequireDefault(require("dom-helpers/querySelectorAll"));
|
9 |
|
10 | var _propTypes = _interopRequireDefault(require("prop-types"));
|
11 |
|
12 | var _react = _interopRequireWildcard(require("react"));
|
13 |
|
14 | var _uncontrollable = require("uncontrollable");
|
15 |
|
16 | var _Button = _interopRequireDefault(require("./Button"));
|
17 |
|
18 | var _DateTimePartInput = _interopRequireDefault(require("./DateTimePartInput"));
|
19 |
|
20 | var _Icon = require("./Icon");
|
21 |
|
22 | var _Widget = _interopRequireDefault(require("./Widget"));
|
23 |
|
24 | var _dates = _interopRequireDefault(require("./dates"));
|
25 |
|
26 | var _useFocusManager = _interopRequireDefault(require("./useFocusManager"));
|
27 |
|
28 | const _excluded = ["value", "use12HourClock", "padValues", "emptyCharacter", "precision", "noClearButton", "hoursAddon", "minutesAddon", "secondsAddon", "millisecondsAddon", "className", "disabled", "readOnly", "datePart", "onChange", "onBlur", "onFocus"];
|
29 |
|
30 | function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
31 |
|
32 | function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
33 |
|
34 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
35 |
|
36 | function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
37 |
|
38 | function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
39 |
|
40 | const selectTextRange = el => {
|
41 | if (el instanceof HTMLInputElement) return el.select();
|
42 | const range = document.createRange();
|
43 | range.selectNodeContents(el);
|
44 | const selection = window.getSelection();
|
45 |
|
46 | if (selection) {
|
47 | selection.removeAllRanges();
|
48 | selection.addRange(range);
|
49 | }
|
50 | };
|
51 |
|
52 |
|
53 | const isEmptyValue = (p, precision) => p.hours == null && p.minutes == null && (precision != 'seconds' && precision !== 'milliseconds' || p.seconds == null) && (precision !== 'milliseconds' || p.milliseconds == null);
|
54 |
|
55 |
|
56 | const isPartialValue = (p, precision) => p.hours == null || p.minutes == null || (precision === 'seconds' || precision === 'milliseconds') && p.seconds == null || precision === 'milliseconds' && p.milliseconds == null;
|
57 |
|
58 | const getValueParts = (value, use12HourClock) => {
|
59 | let hours, minutes, seconds, milliseconds;
|
60 | let meridiem = 'AM';
|
61 |
|
62 | if (value) {
|
63 | hours = value.getHours();
|
64 |
|
65 | if (use12HourClock) {
|
66 | meridiem = hours < 12 ? 'AM' : 'PM';
|
67 | hours = hours % 12 || 12;
|
68 | }
|
69 |
|
70 | minutes = value.getMinutes();
|
71 | seconds = value.getSeconds();
|
72 | milliseconds = value.getMilliseconds();
|
73 | }
|
74 |
|
75 | return {
|
76 | hours,
|
77 | minutes,
|
78 | seconds,
|
79 | milliseconds,
|
80 | meridiem
|
81 | };
|
82 | };
|
83 |
|
84 | const TEST_VALID = {
|
85 | hours: /^([1]?[0-9]|2[0-3])$/,
|
86 | hours12: /^(1[0-2]|0?[1-9])$/,
|
87 | minutes: /^([0-5]?\d)$/,
|
88 | seconds: /^([0-5]?\d)$/,
|
89 | milliseconds: /^(\d{1,3})$/
|
90 | };
|
91 | const TEST_COMPLETE = {
|
92 | hours: /^([3-9]|\d{2})$/,
|
93 | hours12: /^(\d{2}|[2-9])$/,
|
94 | minutes: /^(d{2}|[6-9])$/,
|
95 | seconds: /^(d{2}|[6-9])$/,
|
96 | milliseconds: /^(\d{3})$/
|
97 | };
|
98 |
|
99 | function testPart(value, part, use12HourClock, tests) {
|
100 | const key = part === 'hours' && use12HourClock ? 'hours12' : part;
|
101 | return tests[key].test(value);
|
102 | }
|
103 |
|
104 | const isValid = (value, part, use12HourClock) => testPart(value, part, use12HourClock, TEST_VALID);
|
105 |
|
106 | const isComplete = (value, part, use12HourClock) => testPart(value, part, use12HourClock, TEST_COMPLETE);
|
107 |
|
108 | const propTypes = {
|
109 | |
110 |
|
111 |
|
112 | value: _propTypes.default.instanceOf(Date),
|
113 |
|
114 | |
115 |
|
116 |
|
117 | onChange: _propTypes.default.func,
|
118 |
|
119 | |
120 |
|
121 |
|
122 |
|
123 |
|
124 | datePart: _propTypes.default.instanceOf(Date),
|
125 |
|
126 | |
127 |
|
128 |
|
129 |
|
130 | use12HourClock: _propTypes.default.bool,
|
131 |
|
132 |
|
133 | padValues: _propTypes.default.bool,
|
134 |
|
135 |
|
136 | emptyCharacter: _propTypes.default.string,
|
137 |
|
138 |
|
139 | noClearButton: _propTypes.default.bool,
|
140 |
|
141 | |
142 |
|
143 |
|
144 | disabled: _propTypes.default.bool,
|
145 |
|
146 | |
147 |
|
148 |
|
149 | readOnly: _propTypes.default.bool,
|
150 |
|
151 |
|
152 | precision: _propTypes.default.oneOf(['minutes', 'seconds', 'milliseconds']).isRequired,
|
153 |
|
154 | |
155 |
|
156 |
|
157 |
|
158 | hoursAddon: _propTypes.default.node,
|
159 |
|
160 | |
161 |
|
162 |
|
163 |
|
164 | minutesAddon: _propTypes.default.node,
|
165 |
|
166 | |
167 |
|
168 |
|
169 |
|
170 | secondsAddon: _propTypes.default.node,
|
171 |
|
172 | |
173 |
|
174 |
|
175 |
|
176 | millisecondsAddon: _propTypes.default.node
|
177 | };
|
178 | const defaultProps = {
|
179 | hoursAddon: ':',
|
180 | padValues: true,
|
181 | precision: 'minutes',
|
182 | emptyCharacter: '-'
|
183 | };
|
184 |
|
185 |
|
186 | function useTimePartState(value, use12HourClock) {
|
187 | const [state, setState] = (0, _react.useState)(() => ({
|
188 | value,
|
189 | use12HourClock,
|
190 | timeParts: getValueParts(value, use12HourClock)
|
191 | }));
|
192 | const setTimeParts = (0, _react.useCallback)(timeParts => setState(s => Object.assign({}, s, {
|
193 | timeParts
|
194 | })), [setState]);
|
195 |
|
196 | if (state.value !== value || state.use12HourClock !== use12HourClock) {
|
197 |
|
198 |
|
199 | setState({
|
200 | value,
|
201 | use12HourClock,
|
202 | timeParts: getValueParts(value, use12HourClock)
|
203 | });
|
204 | }
|
205 |
|
206 | return [state.timeParts, setTimeParts];
|
207 | }
|
208 |
|
209 | function TimeInput(uncontrolledProps) {
|
210 | const _useUncontrolled = (0, _uncontrollable.useUncontrolled)(uncontrolledProps, {
|
211 | value: 'onChange'
|
212 | }),
|
213 | {
|
214 | value,
|
215 | use12HourClock,
|
216 | padValues: pad,
|
217 | emptyCharacter,
|
218 | precision,
|
219 | noClearButton,
|
220 | hoursAddon,
|
221 | minutesAddon,
|
222 | secondsAddon,
|
223 | millisecondsAddon,
|
224 | className,
|
225 | disabled,
|
226 | readOnly,
|
227 | datePart,
|
228 | onChange,
|
229 | onBlur,
|
230 | onFocus
|
231 | } = _useUncontrolled,
|
232 | props = _objectWithoutPropertiesLoose(_useUncontrolled, _excluded);
|
233 |
|
234 | let minsAddon = minutesAddon !== undefined ? minutesAddon : precision === 'seconds' || precision === 'milliseconds' ? ':' : '';
|
235 | let secsAddon = secondsAddon !== undefined ? secondsAddon : precision === 'milliseconds' ? ':' : '';
|
236 | const ref = (0, _react.useRef)(null);
|
237 | const hourRef = (0, _react.useRef)(null);
|
238 | const [focusEvents, focused] = (0, _useFocusManager.default)(ref, {
|
239 | disabled,
|
240 | onBlur,
|
241 | onFocus
|
242 | }, {
|
243 | didHandle: (focused, e) => {
|
244 | var _hourRef$current;
|
245 |
|
246 | if (!focused) return;
|
247 | if (!e.target.dataset.focusable) (_hourRef$current = hourRef.current) == null ? void 0 : _hourRef$current.focus();else select(e.target);
|
248 | }
|
249 | });
|
250 | const [timeParts, setTimeParts] = useTimePartState(value != null ? value : null, use12HourClock != null ? use12HourClock : false);
|
251 |
|
252 | function getDatePart() {
|
253 | return _dates.default.startOf(datePart || new Date(), 'day');
|
254 | }
|
255 |
|
256 | const getMin = part => part === 'hours' ? 1 : 0;
|
257 |
|
258 | const getMax = part => {
|
259 | if (part === 'hours') return use12HourClock ? 12 : 23;
|
260 | if (part === 'milliseconds') return 999;
|
261 | return 59;
|
262 | };
|
263 |
|
264 | function select(target = document.activeElement) {
|
265 | window.Promise.resolve().then(() => {
|
266 | if (focused) selectTextRange(target);
|
267 | });
|
268 | }
|
269 | |
270 |
|
271 |
|
272 |
|
273 |
|
274 | const handleClear = () => {
|
275 | var _hourRef$current2;
|
276 |
|
277 | (_hourRef$current2 = hourRef.current) == null ? void 0 : _hourRef$current2.focus();
|
278 | if (value) onChange(null);else setTimeParts(getValueParts(null));
|
279 | };
|
280 |
|
281 | const handleChange = (part, event) => {
|
282 | const currentValue = timeParts[part];
|
283 | const {
|
284 | target
|
285 | } = event;
|
286 | const rawValue = target.value;
|
287 | let strValue = `${currentValue || ''}${rawValue}`;
|
288 | let numValue = +strValue;
|
289 |
|
290 | if (isNaN(numValue) || strValue && !isValid(strValue, part, use12HourClock != null ? use12HourClock : false)) {
|
291 |
|
292 |
|
293 | if (isValid(rawValue, part, use12HourClock != null ? use12HourClock : false) && !isNaN(+rawValue)) {
|
294 |
|
295 | strValue = rawValue;
|
296 | numValue = +rawValue;
|
297 | } else {
|
298 | return event.preventDefault();
|
299 | }
|
300 | }
|
301 |
|
302 | const nextValue = target.value ? numValue : null;
|
303 | notifyChange({
|
304 | [part]: nextValue
|
305 | });
|
306 |
|
307 | if (nextValue != null && isComplete(strValue, part, use12HourClock != null ? use12HourClock : false)) {
|
308 | focusNext(event.currentTarget, +1);
|
309 | } else {
|
310 | select(target);
|
311 | }
|
312 | };
|
313 |
|
314 | const handleSelect = ({
|
315 | target
|
316 | }) => {
|
317 | select(target);
|
318 | };
|
319 |
|
320 | const handleKeyDown = (part, event) => {
|
321 | const {
|
322 | key
|
323 | } = event;
|
324 | const input = event.currentTarget;
|
325 | const {
|
326 | selectionStart: start,
|
327 | selectionEnd: end
|
328 | } = input;
|
329 | const isRTL = getComputedStyle(input).getPropertyValue('direction') === 'rtl';
|
330 | const isMeridiem = part === 'meridiem';
|
331 | const isNext = key === (isRTL ? 'ArrowLeft' : 'ArrowRight');
|
332 | const isPrev = key === (isRTL ? 'ArrowRight' : 'ArrowLeft');
|
333 |
|
334 | if (key === 'ArrowUp') {
|
335 | event.preventDefault();
|
336 | increment(part, 1);
|
337 | }
|
338 |
|
339 | if (key === 'ArrowDown') {
|
340 | event.preventDefault();
|
341 | increment(part, -1);
|
342 | }
|
343 |
|
344 | if (isPrev && (isMeridiem || start - 1 < 0)) {
|
345 | event.preventDefault();
|
346 | focusNext(input, -1);
|
347 | }
|
348 |
|
349 | if (isNext && (isMeridiem || input.value.length <= end + 1)) {
|
350 | event.preventDefault();
|
351 | focusNext(input, +1);
|
352 | }
|
353 |
|
354 | if (readOnly && key !== 'Tab') {
|
355 | event.preventDefault();
|
356 | }
|
357 |
|
358 | if (isMeridiem) {
|
359 | if (key === 'a' || key === 'A') notifyChange({
|
360 | meridiem: 'AM'
|
361 | });
|
362 | if (key === 'p' || key === 'P') notifyChange({
|
363 | meridiem: 'PM'
|
364 | });
|
365 | }
|
366 | };
|
367 |
|
368 | const increment = (part, inc) => {
|
369 | let nextPart = timeParts[part];
|
370 |
|
371 | if (part === 'meridiem') {
|
372 | nextPart = nextPart === 'AM' ? 'PM' : 'AM';
|
373 | } else {
|
374 | nextPart = (nextPart || 0) + inc;
|
375 | if (!isValid(String(nextPart), part, use12HourClock != null ? use12HourClock : false)) return;
|
376 | }
|
377 |
|
378 | notifyChange({
|
379 | [part]: nextPart
|
380 | });
|
381 | select();
|
382 | };
|
383 |
|
384 | function notifyChange(updates) {
|
385 | const nextTimeParts = Object.assign({}, timeParts, updates);
|
386 |
|
387 | if (value && isEmptyValue(nextTimeParts, precision)) {
|
388 | return onChange(null);
|
389 | }
|
390 |
|
391 | if (isPartialValue(nextTimeParts, precision)) return setTimeParts(nextTimeParts);
|
392 | let {
|
393 | hours,
|
394 | minutes,
|
395 | seconds,
|
396 | milliseconds,
|
397 | meridiem
|
398 | } = nextTimeParts;
|
399 | let nextDate = new Date(value || getDatePart());
|
400 |
|
401 | if (use12HourClock) {
|
402 | if (hours === 12) hours = 0;
|
403 | hours += meridiem === 'PM' ? 12 : 0;
|
404 | }
|
405 |
|
406 | nextDate.setHours(hours);
|
407 | nextDate.setMinutes(minutes);
|
408 | if (seconds != null) nextDate.setSeconds(seconds);
|
409 | if (milliseconds != null) nextDate.setMilliseconds(milliseconds);
|
410 | onChange(nextDate, {
|
411 | lastValue: value,
|
412 | timeParts
|
413 | });
|
414 | }
|
415 |
|
416 | function focusNext(input, delta) {
|
417 | let nodes = (0, _querySelectorAll.default)(ref.current, '* [data-focusable]');
|
418 | let next = nodes[nodes.indexOf(input) + delta];
|
419 | next == null ? void 0 : next.focus();
|
420 | select(next);
|
421 | }
|
422 |
|
423 | const {
|
424 | hours,
|
425 | minutes,
|
426 | seconds,
|
427 | milliseconds,
|
428 | meridiem
|
429 | } = timeParts;
|
430 | const showClear = !isEmptyValue(timeParts, precision);
|
431 | return _react.default.createElement(_Widget.default, _extends({}, props, {
|
432 | role: "group",
|
433 | ref: ref
|
434 | }, focusEvents, {
|
435 | focused: focused,
|
436 | disabled: disabled,
|
437 | readOnly: readOnly,
|
438 | className: (0, _classnames.default)(className, 'rw-time-input rw-widget-input')
|
439 | }), _react.default.createElement(_DateTimePartInput.default, {
|
440 | size: 2,
|
441 | pad: pad ? 2 : undefined,
|
442 | value: hours,
|
443 | disabled: disabled,
|
444 | readOnly: readOnly,
|
445 | "aria-label": "hours",
|
446 | min: getMin('hours'),
|
447 | max: getMax('hours'),
|
448 | ref: hourRef,
|
449 | emptyChar: emptyCharacter,
|
450 | onSelect: handleSelect,
|
451 | onChange: e => handleChange('hours', e),
|
452 | onKeyDown: e => handleKeyDown('hours', e)
|
453 | }), hoursAddon && _react.default.createElement("span", null, hoursAddon), _react.default.createElement(_DateTimePartInput.default, {
|
454 | size: 2,
|
455 | pad: pad ? 2 : undefined,
|
456 | value: minutes,
|
457 | disabled: disabled,
|
458 | readOnly: readOnly,
|
459 | "aria-label": "minutes",
|
460 | min: getMin('minutes'),
|
461 | max: getMax('minutes'),
|
462 | emptyChar: emptyCharacter,
|
463 | onSelect: handleSelect,
|
464 | onChange: e => handleChange('minutes', e),
|
465 | onKeyDown: e => handleKeyDown('minutes', e)
|
466 | }), minsAddon && _react.default.createElement("span", null, minsAddon), (precision === 'seconds' || precision === 'milliseconds') && _react.default.createElement(_react.default.Fragment, null, _react.default.createElement(_DateTimePartInput.default, {
|
467 | size: 2,
|
468 | pad: pad ? 2 : undefined,
|
469 | value: seconds,
|
470 | disabled: disabled,
|
471 | readOnly: readOnly,
|
472 | "aria-label": "seconds",
|
473 | min: getMin('seconds'),
|
474 | max: getMax('seconds'),
|
475 | emptyChar: emptyCharacter,
|
476 | onSelect: handleSelect,
|
477 | onChange: e => handleChange('seconds', e),
|
478 | onKeyDown: e => handleKeyDown('seconds', e)
|
479 | }), secsAddon && _react.default.createElement("span", null, secsAddon)), precision === 'milliseconds' && _react.default.createElement(_react.default.Fragment, null, _react.default.createElement(_DateTimePartInput.default, {
|
480 | size: 3,
|
481 | pad: pad ? 3 : undefined,
|
482 | value: milliseconds,
|
483 | disabled: disabled,
|
484 | readOnly: readOnly,
|
485 | "aria-label": "milliseconds",
|
486 | min: getMin('milliseconds'),
|
487 | max: getMax('milliseconds'),
|
488 | emptyChar: emptyCharacter,
|
489 | onSelect: handleSelect,
|
490 | onChange: e => handleChange('milliseconds', e),
|
491 | onKeyDown: e => handleKeyDown('milliseconds', e)
|
492 | }), millisecondsAddon && _react.default.createElement("span", null, millisecondsAddon)), use12HourClock && _react.default.createElement("div", {
|
493 | role: "listbox",
|
494 | "aria-label": "AM/PM",
|
495 | "aria-disabled": disabled,
|
496 | "aria-readonly": readOnly,
|
497 | className: "rw-time-part-meridiem"
|
498 | }, _react.default.createElement("div", {
|
499 | "data-focusable": true,
|
500 | role: "option",
|
501 | "aria-atomic": true,
|
502 | "aria-selected": true,
|
503 | "aria-setsize": 2,
|
504 | "aria-live": "assertive",
|
505 | "aria-disabled": disabled,
|
506 | "aria-readonly": readOnly,
|
507 | "aria-posinset": meridiem === 'AM' ? 1 : 2,
|
508 | tabIndex: !disabled ? 0 : void 0,
|
509 | onFocus: handleSelect,
|
510 | onSelect: handleSelect,
|
511 | onKeyDown: e => handleKeyDown('meridiem', e)
|
512 | }, _react.default.createElement("abbr", null, meridiem))), !noClearButton && _react.default.createElement(_Button.default, {
|
513 | label: 'clear input',
|
514 | onClick: handleClear,
|
515 | disabled: disabled || readOnly,
|
516 | className: (0, _classnames.default)('rw-time-input-clear', showClear && 'rw-show')
|
517 | }, _Icon.times));
|
518 | }
|
519 |
|
520 | TimeInput.propTypes = propTypes;
|
521 | TimeInput.defaultProps = defaultProps;
|
522 | var _default = TimeInput;
|
523 | exports.default = _default; |
\ | No newline at end of file |