1 | const _excluded = ["id", "value", "onChange", "onSelect", "onToggle", "onKeyDown", "onKeyPress", "onCurrentDateChange", "inputProps", "calendarProps", "timeInputProps", "autoFocus", "tabIndex", "disabled", "readOnly", "className", "valueFormat", "valueDisplayFormat", "valueEditFormat", "containerClassName", "name", "selectIcon", "placeholder", "includeTime", "min", "max", "open", "dropUp", "parse", "messages", "formats", "currentDate", "popupTransition", "popupComponent", "timePrecision", "aria-labelledby", "aria-describedby"];
|
2 |
|
3 | 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); }
|
4 |
|
5 | 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; }
|
6 |
|
7 | import cn from 'classnames';
|
8 | import PropTypes from 'prop-types';
|
9 | import React, { useImperativeHandle, useRef, useCallback } from 'react';
|
10 | import { useUncontrolled } from 'uncontrollable';
|
11 | import Calendar from './Calendar';
|
12 | import DatePickerInput from './DatePickerInput';
|
13 | import { calendar } from './Icon';
|
14 | import { useLocalizer } from './Localization';
|
15 | import BasePopup from './Popup';
|
16 | import TimeInput from './TimeInput';
|
17 | import Widget from './Widget';
|
18 | import WidgetPicker from './WidgetPicker';
|
19 | import dates from './dates';
|
20 | import useDropdownToggle from './useDropdownToggle';
|
21 | import useTabTrap from './useTabTrap';
|
22 | import useFocusManager from './useFocusManager';
|
23 | import { notify, useFirstFocusedRender, useInstanceId } from './WidgetHelpers';
|
24 | import useEventCallback from '@restart/hooks/useEventCallback';
|
25 | import InputAddon from './InputAddon';
|
26 | let propTypes = {
|
27 | |
28 |
|
29 |
|
30 | value: PropTypes.instanceOf(Date),
|
31 |
|
32 | |
33 |
|
34 |
|
35 | onChange: PropTypes.func,
|
36 |
|
37 | |
38 |
|
39 |
|
40 | open: PropTypes.bool,
|
41 | onToggle: PropTypes.func,
|
42 |
|
43 | |
44 |
|
45 |
|
46 | currentDate: PropTypes.instanceOf(Date),
|
47 |
|
48 | |
49 |
|
50 |
|
51 | onCurrentDateChange: PropTypes.func,
|
52 | onSelect: PropTypes.func,
|
53 |
|
54 | |
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 | min: PropTypes.instanceOf(Date),
|
62 |
|
63 | |
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 | max: PropTypes.instanceOf(Date),
|
71 |
|
72 | |
73 |
|
74 |
|
75 |
|
76 | valueFormat: PropTypes.any,
|
77 |
|
78 | |
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 | valueDisplayFormat: PropTypes.any,
|
92 |
|
93 | |
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 | valueEditFormat: PropTypes.any,
|
108 |
|
109 | |
110 |
|
111 |
|
112 | includeTime: PropTypes.bool,
|
113 | timePrecision: PropTypes.oneOf(['minutes', 'seconds', 'milliseconds']),
|
114 | timeInputProps: PropTypes.object,
|
115 |
|
116 |
|
117 | selectIcon: PropTypes.node,
|
118 | dropUp: PropTypes.bool,
|
119 | popupTransition: PropTypes.elementType,
|
120 | placeholder: PropTypes.string,
|
121 | name: PropTypes.string,
|
122 | autoFocus: PropTypes.bool,
|
123 |
|
124 | |
125 |
|
126 |
|
127 | disabled: PropTypes.bool,
|
128 |
|
129 | |
130 |
|
131 |
|
132 | readOnly: PropTypes.bool,
|
133 |
|
134 | |
135 |
|
136 |
|
137 |
|
138 |
|
139 | parse: PropTypes.oneOfType([PropTypes.any, PropTypes.func]),
|
140 |
|
141 |
|
142 | tabIndex: PropTypes.any,
|
143 |
|
144 |
|
145 | 'aria-labelledby': PropTypes.string,
|
146 |
|
147 |
|
148 | 'aria-describedby': PropTypes.string,
|
149 |
|
150 |
|
151 | localizer: PropTypes.any,
|
152 | onKeyDown: PropTypes.func,
|
153 | onKeyPress: PropTypes.func,
|
154 | onBlur: PropTypes.func,
|
155 | onFocus: PropTypes.func,
|
156 |
|
157 |
|
158 | containerClassName: PropTypes.string,
|
159 | calendarProps: PropTypes.object,
|
160 | inputProps: PropTypes.object,
|
161 | messages: PropTypes.shape({
|
162 | dateButton: PropTypes.string
|
163 | })
|
164 | };
|
165 | const defaultProps = Object.assign({}, Calendar.defaultProps, {
|
166 | min: new Date(1900, 0, 1),
|
167 | max: new Date(2099, 11, 31),
|
168 | selectIcon: calendar,
|
169 | formats: {}
|
170 | });
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 | const DatePicker = React.forwardRef((uncontrolledProps, outerRef) => {
|
191 | const _useUncontrolled = useUncontrolled(uncontrolledProps, {
|
192 | open: 'onToggle',
|
193 | value: 'onChange',
|
194 | currentDate: 'onCurrentDateChange'
|
195 | }),
|
196 | {
|
197 | id,
|
198 | value,
|
199 | onChange,
|
200 | onSelect,
|
201 | onToggle,
|
202 | onKeyDown,
|
203 | onKeyPress,
|
204 | onCurrentDateChange,
|
205 | inputProps,
|
206 | calendarProps,
|
207 | timeInputProps,
|
208 | autoFocus,
|
209 | tabIndex,
|
210 | disabled,
|
211 | readOnly,
|
212 | className,
|
213 |
|
214 | valueFormat,
|
215 | valueDisplayFormat = valueFormat,
|
216 | valueEditFormat = valueFormat,
|
217 | containerClassName,
|
218 | name,
|
219 | selectIcon,
|
220 | placeholder,
|
221 | includeTime = false,
|
222 | min,
|
223 | max,
|
224 | open,
|
225 | dropUp,
|
226 | parse,
|
227 | messages,
|
228 | formats,
|
229 | currentDate,
|
230 | popupTransition,
|
231 | popupComponent: Popup = BasePopup,
|
232 | timePrecision,
|
233 | 'aria-labelledby': ariaLabelledby,
|
234 | 'aria-describedby': ariaDescribedby
|
235 | } = _useUncontrolled,
|
236 | elementProps = _objectWithoutPropertiesLoose(_useUncontrolled, _excluded);
|
237 |
|
238 | const localizer = useLocalizer(messages, formats);
|
239 | const ref = useRef(null);
|
240 | const calRef = useRef(null);
|
241 | const tabTrap = useTabTrap(calRef);
|
242 | const inputId = useInstanceId(id, '_input');
|
243 | const dateId = useInstanceId(id, '_date');
|
244 | const currentFormat = includeTime ? 'datetime' : 'date';
|
245 | const toggle = useDropdownToggle(open, onToggle);
|
246 | const [focusEvents, focused] = useFocusManager(ref, uncontrolledProps, {
|
247 | didHandle(focused) {
|
248 | if (!focused) {
|
249 | toggle.close();
|
250 | tabTrap.stop();
|
251 | } else if (open) {
|
252 | tabTrap.focus();
|
253 | }
|
254 | }
|
255 |
|
256 | });
|
257 | const dateParser = useCallback(str => {
|
258 | var _localizer$parseDate, _ref;
|
259 |
|
260 | if (typeof parse == 'function') {
|
261 | var _parse;
|
262 |
|
263 | return (_parse = parse(str, localizer)) != null ? _parse : null;
|
264 | }
|
265 |
|
266 | return (_localizer$parseDate = localizer.parseDate(str, (_ref = parse != null ? parse : valueEditFormat) != null ? _ref : valueDisplayFormat)) != null ? _localizer$parseDate : null;
|
267 | }, [localizer, parse, valueDisplayFormat, valueEditFormat]);
|
268 | |
269 |
|
270 |
|
271 |
|
272 | const handleChange = useEventCallback((date, str, constrain) => {
|
273 | if (readOnly || disabled) return;
|
274 | if (constrain) date = inRangeValue(date);
|
275 |
|
276 | if (onChange) {
|
277 | if (date == null || value == null) {
|
278 | if (date != value
|
279 | ) onChange(date, str);
|
280 | } else if (!dates.eq(date, value)) {
|
281 | onChange(date, str);
|
282 | }
|
283 | }
|
284 | });
|
285 | const handleKeyDown = useEventCallback(e => {
|
286 | if (readOnly) return;
|
287 | notify(onKeyDown, [e]);
|
288 | if (e.defaultPrevented) return;
|
289 |
|
290 | if (e.key === 'Escape' && open) {
|
291 | toggle.close();
|
292 | } else if (e.altKey) {
|
293 | if (e.key === 'ArrowDown') {
|
294 | e.preventDefault();
|
295 | toggle.open();
|
296 | } else if (e.key === 'ArrowUp') {
|
297 | e.preventDefault();
|
298 | toggle.close();
|
299 | }
|
300 | }
|
301 | });
|
302 | const handleKeyPress = useEventCallback(e => {
|
303 | notify(onKeyPress, [e]);
|
304 | if (e.defaultPrevented) return;
|
305 | });
|
306 | const handleDateSelect = useEventCallback(date => {
|
307 | var _ref$current;
|
308 |
|
309 | let dateTime = dates.merge(date, value, currentDate);
|
310 | let dateStr = formatDate(date);
|
311 | if (!includeTime) toggle.close();
|
312 | notify(onSelect, [dateTime, dateStr]);
|
313 | handleChange(dateTime, dateStr, true);
|
314 | (_ref$current = ref.current) == null ? void 0 : _ref$current.focus();
|
315 | });
|
316 | const handleTimeChange = useEventCallback(date => {
|
317 | handleChange(date, formatDate(date), true);
|
318 | });
|
319 | const handleCalendarClick = useEventCallback(e => {
|
320 | if (readOnly || disabled) return;
|
321 |
|
322 | e.preventDefault();
|
323 | toggle();
|
324 | });
|
325 |
|
326 | const handleOpening = () => {
|
327 | tabTrap.start();
|
328 | requestAnimationFrame(() => {
|
329 | tabTrap.focus();
|
330 | });
|
331 | };
|
332 |
|
333 | const handleClosing = () => {
|
334 | tabTrap.stop();
|
335 | if (focused) focus();
|
336 | };
|
337 | |
338 |
|
339 |
|
340 |
|
341 |
|
342 | function focus() {
|
343 | var _calRef$current, _ref$current2;
|
344 |
|
345 | if (open) (_calRef$current = calRef.current) == null ? void 0 : _calRef$current.focus();else (_ref$current2 = ref.current) == null ? void 0 : _ref$current2.focus();
|
346 | }
|
347 |
|
348 | function inRangeValue(value) {
|
349 | if (value == null) return value;
|
350 | return dates.max(dates.min(value, max), min);
|
351 | }
|
352 |
|
353 | function formatDate(date) {
|
354 | return date instanceof Date && !isNaN(date.getTime()) ? localizer.formatDate(date, currentFormat) : '';
|
355 | }
|
356 |
|
357 | useImperativeHandle(outerRef, () => ({
|
358 | focus
|
359 | }));
|
360 | let shouldRenderList = useFirstFocusedRender(focused, open);
|
361 | const inputReadOnly = (inputProps == null ? void 0 : inputProps.readOnly) != null ? inputProps == null ? void 0 : inputProps.readOnly : readOnly;
|
362 | return React.createElement(Widget, _extends({}, elementProps, {
|
363 | defaultValue: undefined,
|
364 | open: !!open,
|
365 | dropUp: dropUp,
|
366 | focused: focused,
|
367 | disabled: disabled,
|
368 | readOnly: readOnly,
|
369 | onKeyDown: handleKeyDown,
|
370 | onKeyPress: handleKeyPress
|
371 | }, focusEvents, {
|
372 | className: cn(className, 'rw-date-picker')
|
373 | }), React.createElement(WidgetPicker, {
|
374 | className: containerClassName
|
375 | }, React.createElement(DatePickerInput, _extends({}, inputProps, {
|
376 | id: inputId,
|
377 | ref: ref,
|
378 | role: "combobox",
|
379 | name: name,
|
380 | value: value,
|
381 | tabIndex: tabIndex,
|
382 | autoFocus: autoFocus,
|
383 | placeholder: placeholder,
|
384 | disabled: disabled,
|
385 | readOnly: inputReadOnly,
|
386 | formatter: currentFormat,
|
387 | displayFormat: valueDisplayFormat,
|
388 | editFormat: valueEditFormat,
|
389 | editing: focused,
|
390 | localizer: localizer,
|
391 | parse: dateParser,
|
392 | onChange: handleChange,
|
393 | "aria-haspopup": true,
|
394 | "aria-labelledby": ariaLabelledby,
|
395 | "aria-describedby": ariaDescribedby,
|
396 | "aria-expanded": !!open,
|
397 | "aria-owns": dateId
|
398 | })), React.createElement(InputAddon, {
|
399 | icon: selectIcon,
|
400 | label: localizer.messages.dateButton(),
|
401 | disabled: disabled || readOnly,
|
402 | onClick: handleCalendarClick
|
403 | })), !!shouldRenderList && React.createElement(Popup, {
|
404 | dropUp: dropUp,
|
405 | open: open,
|
406 | role: "dialog",
|
407 | ref: calRef,
|
408 | id: dateId,
|
409 | className: "rw-calendar-popup",
|
410 | transition: popupTransition,
|
411 | onEntering: handleOpening,
|
412 | onExited: handleClosing
|
413 | }, React.createElement(Calendar, _extends({
|
414 | min: min,
|
415 | max: max,
|
416 | bordered: false
|
417 | }, calendarProps, {
|
418 | messages: Object.assign({}, messages, calendarProps == null ? void 0 : calendarProps.messages),
|
419 | tabIndex: -1,
|
420 | value: value,
|
421 | autoFocus: false,
|
422 | onChange: handleDateSelect,
|
423 | currentDate: currentDate,
|
424 | onCurrentDateChange: onCurrentDateChange,
|
425 | "aria-hidden": !open,
|
426 | "aria-live": "polite",
|
427 | "aria-labelledby": inputId
|
428 | })), includeTime && React.createElement(TimeInput, _extends({}, timeInputProps, {
|
429 | value: value,
|
430 | precision: timePrecision,
|
431 | onChange: handleTimeChange,
|
432 | datePart: currentDate
|
433 | }))));
|
434 | });
|
435 | DatePicker.displayName = 'DatePicker';
|
436 | DatePicker.propTypes = propTypes;
|
437 | DatePicker.defaultProps = defaultProps;
|
438 | export default DatePicker; |
\ | No newline at end of file |