UNPKG

16.5 kBJavaScriptView Raw
1"use strict";
2
3exports.__esModule = true;
4exports.default = void 0;
5
6var _classnames = _interopRequireDefault(require("classnames"));
7
8var _propTypes = _interopRequireDefault(require("prop-types"));
9
10var _react = _interopRequireWildcard(require("react"));
11
12var _uncontrollable = require("uncontrollable");
13
14var _Calendar = _interopRequireDefault(require("./Calendar"));
15
16var _DatePickerInput = _interopRequireDefault(require("./DatePickerInput"));
17
18var _Icon = require("./Icon");
19
20var _Localization = require("./Localization");
21
22var _Popup = _interopRequireDefault(require("./Popup"));
23
24var _TimeInput = _interopRequireDefault(require("./TimeInput"));
25
26var _Widget = _interopRequireDefault(require("./Widget"));
27
28var _WidgetPicker = _interopRequireDefault(require("./WidgetPicker"));
29
30var _dates = _interopRequireDefault(require("./dates"));
31
32var _useDropdownToggle = _interopRequireDefault(require("./useDropdownToggle"));
33
34var _useTabTrap = _interopRequireDefault(require("./useTabTrap"));
35
36var _useFocusManager = _interopRequireDefault(require("./useFocusManager"));
37
38var _WidgetHelpers = require("./WidgetHelpers");
39
40var _useEventCallback = _interopRequireDefault(require("@restart/hooks/useEventCallback"));
41
42var _InputAddon = _interopRequireDefault(require("./InputAddon"));
43
44const _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"];
45
46function _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); }
47
48function _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; }
49
50function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
51
52function _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); }
53
54function _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; }
55
56let propTypes = {
57 /**
58 * @example ['valuePicker', [ ['new Date()', null] ]]
59 */
60 value: _propTypes.default.instanceOf(Date),
61
62 /**
63 * @example ['onChangePicker', [ ['new Date()', null] ]]
64 */
65 onChange: _propTypes.default.func,
66
67 /**
68 * @example ['openDate']
69 */
70 open: _propTypes.default.bool,
71 onToggle: _propTypes.default.func,
72
73 /**
74 * Default current date at which the calendar opens. If none is provided, opens at today's date or the `value` date (if any).
75 */
76 currentDate: _propTypes.default.instanceOf(Date),
77
78 /**
79 * Change event Handler that is called when the currentDate is changed. The handler is called with the currentDate object.
80 */
81 onCurrentDateChange: _propTypes.default.func,
82 onSelect: _propTypes.default.func,
83
84 /**
85 * The minimum Date that can be selected. Min only limits selection, it doesn't constrain the date values that
86 * can be typed or pasted into the widget. If you need this behavior you can constrain values via
87 * the `onChange` handler.
88 *
89 * @example ['prop', ['min', 'new Date()']]
90 */
91 min: _propTypes.default.instanceOf(Date),
92
93 /**
94 * The maximum Date that can be selected. Max only limits selection, it doesn't constrain the date values that
95 * can be typed or pasted into the widget. If you need this behavior you can constrain values via
96 * the `onChange` handler.
97 *
98 * @example ['prop', ['max', 'new Date()']]
99 */
100 max: _propTypes.default.instanceOf(Date),
101
102 /**
103 * A formatting options used to display the date value. This is a shorthand for
104 * setting both `valueDisplayFormat` and `valueEditFormat`.
105 */
106 valueFormat: _propTypes.default.any,
107
108 /**
109 * A formatting options used to display the date value. For more information about formats
110 * visit the [Localization page](./localization)
111 *
112 * ```tsx live
113 * import { DatePicker } from 'react-widgets';
114 *
115 * <DatePicker
116 * defaultValue={new Date()}
117 * valueDisplayFormat={{ dateStyle: "medium" }}
118 * />
119 * ```
120 */
121 valueDisplayFormat: _propTypes.default.any,
122
123 /**
124 * A formatting options used while the date input has focus. Useful for showing a simpler format for inputing.
125 * For more information about formats visit the [Localization page](./localization)
126 *
127 * ```tsx live
128 * import { DatePicker } from 'react-widgets';
129 *
130 * <DatePicker
131 * defaultValue={new Date()}
132 * valueEditFormat={{ dateStyle: "short" }}
133 * valueDisplayFormat={{ dateStyle: "medium" }}
134 * />
135 * ```
136 */
137 valueEditFormat: _propTypes.default.any,
138
139 /**
140 * Enable the time list component of the picker.
141 */
142 includeTime: _propTypes.default.bool,
143 timePrecision: _propTypes.default.oneOf(['minutes', 'seconds', 'milliseconds']),
144 timeInputProps: _propTypes.default.object,
145
146 /** Specify the element used to render the calendar dropdown icon. */
147 selectIcon: _propTypes.default.node,
148 dropUp: _propTypes.default.bool,
149 popupTransition: _propTypes.default.elementType,
150 placeholder: _propTypes.default.string,
151 name: _propTypes.default.string,
152 autoFocus: _propTypes.default.bool,
153
154 /**
155 * @example ['disabled', ['new Date()']]
156 */
157 disabled: _propTypes.default.bool,
158
159 /**
160 * @example ['readOnly', ['new Date()']]
161 */
162 readOnly: _propTypes.default.bool,
163
164 /**
165 * Determines how the widget parses the typed date string into a Date object. You can provide an array of formats to try,
166 * or provide a function that returns a date to handle parsing yourself. When `parse` is unspecified and
167 * the `format` prop is a `string` parse will automatically use that format as its default.
168 */
169 parse: _propTypes.default.oneOfType([_propTypes.default.any, _propTypes.default.func]),
170
171 /** @ignore */
172 tabIndex: _propTypes.default.any,
173
174 /** @ignore */
175 'aria-labelledby': _propTypes.default.string,
176
177 /** @ignore */
178 'aria-describedby': _propTypes.default.string,
179
180 /** @ignore */
181 localizer: _propTypes.default.any,
182 onKeyDown: _propTypes.default.func,
183 onKeyPress: _propTypes.default.func,
184 onBlur: _propTypes.default.func,
185 onFocus: _propTypes.default.func,
186
187 /** Adds a css class to the input container element. */
188 containerClassName: _propTypes.default.string,
189 calendarProps: _propTypes.default.object,
190 inputProps: _propTypes.default.object,
191 messages: _propTypes.default.shape({
192 dateButton: _propTypes.default.string
193 })
194};
195const defaultProps = Object.assign({}, _Calendar.default.defaultProps, {
196 min: new Date(1900, 0, 1),
197 max: new Date(2099, 11, 31),
198 selectIcon: _Icon.calendar,
199 formats: {}
200});
201
202/**
203 * ---
204 * subtitle: DatePicker, TimePicker
205 * localized: true
206 * shortcuts:
207 * - { key: alt + down arrow, label: open calendar or time }
208 * - { key: alt + up arrow, label: close calendar or time }
209 * - { key: down arrow, label: move focus to next item }
210 * - { key: up arrow, label: move focus to previous item }
211 * - { key: home, label: move focus to first item }
212 * - { key: end, label: move focus to last item }
213 * - { key: enter, label: select focused item }
214 * - { key: any key, label: search list for item starting with key }
215 * ---
216 *
217 * @public
218 * @extends Calendar
219 */
220const DatePicker = /*#__PURE__*/_react.default.forwardRef((uncontrolledProps, outerRef) => {
221 const _useUncontrolled = (0, _uncontrollable.useUncontrolled)(uncontrolledProps, {
222 open: 'onToggle',
223 value: 'onChange',
224 currentDate: 'onCurrentDateChange'
225 }),
226 {
227 id,
228 value,
229 onChange,
230 onSelect,
231 onToggle,
232 onKeyDown,
233 onKeyPress,
234 onCurrentDateChange,
235 inputProps,
236 calendarProps,
237 timeInputProps,
238 autoFocus,
239 tabIndex,
240 disabled,
241 readOnly,
242 className,
243 // @ts-ignore
244 valueFormat,
245 valueDisplayFormat = valueFormat,
246 valueEditFormat = valueFormat,
247 containerClassName,
248 name,
249 selectIcon,
250 placeholder,
251 includeTime = false,
252 min,
253 max,
254 open,
255 dropUp,
256 parse,
257 messages,
258 formats,
259 currentDate,
260 popupTransition,
261 popupComponent: Popup = _Popup.default,
262 timePrecision,
263 'aria-labelledby': ariaLabelledby,
264 'aria-describedby': ariaDescribedby
265 } = _useUncontrolled,
266 elementProps = _objectWithoutPropertiesLoose(_useUncontrolled, _excluded);
267
268 const localizer = (0, _Localization.useLocalizer)(messages, formats);
269 const ref = (0, _react.useRef)(null);
270 const calRef = (0, _react.useRef)(null);
271 const tabTrap = (0, _useTabTrap.default)(calRef);
272 const inputId = (0, _WidgetHelpers.useInstanceId)(id, '_input');
273 const dateId = (0, _WidgetHelpers.useInstanceId)(id, '_date');
274 const currentFormat = includeTime ? 'datetime' : 'date';
275 const toggle = (0, _useDropdownToggle.default)(open, onToggle);
276 const [focusEvents, focused] = (0, _useFocusManager.default)(ref, uncontrolledProps, {
277 didHandle(focused) {
278 if (!focused) {
279 toggle.close();
280 tabTrap.stop();
281 } else if (open) {
282 tabTrap.focus();
283 }
284 }
285
286 });
287 const dateParser = (0, _react.useCallback)(str => {
288 var _localizer$parseDate, _ref;
289
290 if (typeof parse == 'function') {
291 var _parse;
292
293 return (_parse = parse(str, localizer)) != null ? _parse : null;
294 }
295
296 return (_localizer$parseDate = localizer.parseDate(str, (_ref = parse != null ? parse : valueEditFormat) != null ? _ref : valueDisplayFormat)) != null ? _localizer$parseDate : null;
297 }, [localizer, parse, valueDisplayFormat, valueEditFormat]);
298 /**
299 * Handlers
300 */
301
302 const handleChange = (0, _useEventCallback.default)((date, str, constrain) => {
303 if (readOnly || disabled) return;
304 if (constrain) date = inRangeValue(date);
305
306 if (onChange) {
307 if (date == null || value == null) {
308 if (date != value //eslint-disable-line eqeqeq
309 ) onChange(date, str);
310 } else if (!_dates.default.eq(date, value)) {
311 onChange(date, str);
312 }
313 }
314 });
315 const handleKeyDown = (0, _useEventCallback.default)(e => {
316 if (readOnly) return;
317 (0, _WidgetHelpers.notify)(onKeyDown, [e]);
318 if (e.defaultPrevented) return;
319
320 if (e.key === 'Escape' && open) {
321 toggle.close();
322 } else if (e.altKey) {
323 if (e.key === 'ArrowDown') {
324 e.preventDefault();
325 toggle.open();
326 } else if (e.key === 'ArrowUp') {
327 e.preventDefault();
328 toggle.close();
329 }
330 }
331 });
332 const handleKeyPress = (0, _useEventCallback.default)(e => {
333 (0, _WidgetHelpers.notify)(onKeyPress, [e]);
334 if (e.defaultPrevented) return;
335 });
336 const handleDateSelect = (0, _useEventCallback.default)(date => {
337 var _ref$current;
338
339 let dateTime = _dates.default.merge(date, value, currentDate);
340
341 let dateStr = formatDate(date);
342 if (!includeTime) toggle.close();
343 (0, _WidgetHelpers.notify)(onSelect, [dateTime, dateStr]);
344 handleChange(dateTime, dateStr, true);
345 (_ref$current = ref.current) == null ? void 0 : _ref$current.focus();
346 });
347 const handleTimeChange = (0, _useEventCallback.default)(date => {
348 handleChange(date, formatDate(date), true);
349 });
350 const handleCalendarClick = (0, _useEventCallback.default)(e => {
351 if (readOnly || disabled) return; // prevents double clicks when in a <label>
352
353 e.preventDefault();
354 toggle();
355 });
356
357 const handleOpening = () => {
358 tabTrap.start();
359 requestAnimationFrame(() => {
360 tabTrap.focus();
361 });
362 };
363
364 const handleClosing = () => {
365 tabTrap.stop();
366 if (focused) focus();
367 };
368 /**
369 * Methods
370 */
371
372
373 function focus() {
374 var _calRef$current, _ref$current2;
375
376 if (open) (_calRef$current = calRef.current) == null ? void 0 : _calRef$current.focus();else (_ref$current2 = ref.current) == null ? void 0 : _ref$current2.focus();
377 }
378
379 function inRangeValue(value) {
380 if (value == null) return value;
381 return _dates.default.max(_dates.default.min(value, max), min);
382 }
383
384 function formatDate(date) {
385 return date instanceof Date && !isNaN(date.getTime()) ? localizer.formatDate(date, currentFormat) : '';
386 }
387
388 (0, _react.useImperativeHandle)(outerRef, () => ({
389 focus
390 }));
391 let shouldRenderList = (0, _WidgetHelpers.useFirstFocusedRender)(focused, open);
392 const inputReadOnly = (inputProps == null ? void 0 : inputProps.readOnly) != null ? inputProps == null ? void 0 : inputProps.readOnly : readOnly;
393 return /*#__PURE__*/_react.default.createElement(_Widget.default, _extends({}, elementProps, {
394 defaultValue: undefined,
395 open: !!open,
396 dropUp: dropUp,
397 focused: focused,
398 disabled: disabled,
399 readOnly: readOnly,
400 onKeyDown: handleKeyDown,
401 onKeyPress: handleKeyPress
402 }, focusEvents, {
403 className: (0, _classnames.default)(className, 'rw-date-picker')
404 }), /*#__PURE__*/_react.default.createElement(_WidgetPicker.default, {
405 className: containerClassName
406 }, /*#__PURE__*/_react.default.createElement(_DatePickerInput.default, _extends({}, inputProps, {
407 id: inputId,
408 ref: ref,
409 role: "combobox",
410 name: name,
411 value: value,
412 tabIndex: tabIndex,
413 autoFocus: autoFocus,
414 placeholder: placeholder,
415 disabled: disabled,
416 readOnly: inputReadOnly,
417 formatter: currentFormat,
418 displayFormat: valueDisplayFormat,
419 editFormat: valueEditFormat,
420 editing: focused,
421 localizer: localizer,
422 parse: dateParser,
423 onChange: handleChange,
424 "aria-haspopup": true,
425 "aria-labelledby": ariaLabelledby,
426 "aria-describedby": ariaDescribedby,
427 "aria-expanded": !!open,
428 "aria-owns": dateId
429 })), /*#__PURE__*/_react.default.createElement(_InputAddon.default, {
430 icon: selectIcon,
431 label: localizer.messages.dateButton(),
432 disabled: disabled || readOnly,
433 onClick: handleCalendarClick
434 })), !!shouldRenderList && /*#__PURE__*/_react.default.createElement(Popup, {
435 dropUp: dropUp,
436 open: open,
437 role: "dialog",
438 ref: calRef,
439 id: dateId,
440 className: "rw-calendar-popup",
441 transition: popupTransition,
442 onEntering: handleOpening,
443 onExited: handleClosing
444 }, /*#__PURE__*/_react.default.createElement(_Calendar.default, _extends({
445 min: min,
446 max: max,
447 bordered: false
448 }, calendarProps, {
449 messages: Object.assign({}, messages, calendarProps == null ? void 0 : calendarProps.messages),
450 tabIndex: -1,
451 value: value,
452 autoFocus: false,
453 onChange: handleDateSelect,
454 currentDate: currentDate,
455 onCurrentDateChange: onCurrentDateChange,
456 "aria-hidden": !open,
457 "aria-live": "polite",
458 "aria-labelledby": inputId
459 })), includeTime && /*#__PURE__*/_react.default.createElement(_TimeInput.default, _extends({}, timeInputProps, {
460 value: value,
461 precision: timePrecision,
462 onChange: handleTimeChange,
463 datePart: currentDate
464 }))));
465});
466
467DatePicker.displayName = 'DatePicker';
468DatePicker.propTypes = propTypes;
469DatePicker.defaultProps = defaultProps;
470var _default = DatePicker;
471exports.default = _default;
\No newline at end of file