wf-react-day-picker 0.0.1-security → 2.653.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of wf-react-day-picker might be problematic. Click here for more details.

@@ -0,0 +1,601 @@
1
+ import React, {Component} from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ import Caption from './Caption';
5
+ import Navbar from './Navbar';
6
+ import Month from './Month';
7
+ import Weekday from './Weekday';
8
+
9
+ import * as Helpers from './Helpers';
10
+ import * as DateUtils from './DateUtils';
11
+ import * as LocaleUtils from './LocaleUtils';
12
+ import * as ModifiersUtils from './ModifiersUtils';
13
+ import classNames from './classNames';
14
+
15
+ import {ENTER, SPACE, LEFT, UP, DOWN, RIGHT} from './keys';
16
+
17
+ export class DayPicker extends Component {
18
+ static VERSION = '7.1.8';
19
+
20
+ static propTypes = {
21
+ // Rendering months
22
+ initialMonth: PropTypes.instanceOf(Date),
23
+ month: PropTypes.instanceOf(Date),
24
+ numberOfMonths: PropTypes.number,
25
+ fromMonth: PropTypes.instanceOf(Date),
26
+ toMonth: PropTypes.instanceOf(Date),
27
+ canChangeMonth: PropTypes.bool,
28
+ reverseMonths: PropTypes.bool,
29
+ pagedNavigation: PropTypes.bool,
30
+ todayButton: PropTypes.string,
31
+ showWeekNumbers: PropTypes.bool,
32
+ showWeekDays: PropTypes.bool,
33
+
34
+ // Modifiers
35
+ selectedDays: PropTypes.oneOfType([
36
+ PropTypes.object,
37
+ PropTypes.func,
38
+ PropTypes.array,
39
+ ]),
40
+ disabledDays: PropTypes.oneOfType([
41
+ PropTypes.object,
42
+ PropTypes.func,
43
+ PropTypes.array,
44
+ ]),
45
+
46
+ modifiers: PropTypes.object,
47
+ modifiersStyles: PropTypes.object,
48
+
49
+ // Localization
50
+ dir: PropTypes.string,
51
+ firstDayOfWeek: PropTypes.oneOf([0, 1, 2, 3, 4, 5, 6]),
52
+ labels: PropTypes.shape({
53
+ nextMonth: PropTypes.node.isRequired,
54
+ previousMonth: PropTypes.node.isRequired,
55
+ }),
56
+ locale: PropTypes.string,
57
+ localeUtils: PropTypes.shape({
58
+ formatMonthTitle: PropTypes.func,
59
+ formatWeekdayShort: PropTypes.func,
60
+ formatWeekdayLong: PropTypes.func,
61
+ getFirstDayOfWeek: PropTypes.func,
62
+ }),
63
+ months: PropTypes.arrayOf(PropTypes.node),
64
+ weekdaysLong: PropTypes.arrayOf(PropTypes.node),
65
+ weekdaysShort: PropTypes.arrayOf(PropTypes.node),
66
+
67
+ // Customization
68
+ showOutsideDays: PropTypes.bool,
69
+ enableOutsideDaysClick: PropTypes.bool,
70
+ fixedWeeks: PropTypes.bool,
71
+
72
+ // CSS and HTML
73
+ classNames: PropTypes.shape({
74
+ body: PropTypes.string,
75
+ container: PropTypes.string,
76
+ day: PropTypes.string.isRequired,
77
+ disabled: PropTypes.string.isRequired,
78
+ footer: PropTypes.string,
79
+ interactionDisabled: PropTypes.string,
80
+ months: PropTypes.string,
81
+ month: PropTypes.string,
82
+ navBar: PropTypes.string,
83
+ outside: PropTypes.string.isRequired,
84
+ selected: PropTypes.string.isRequired,
85
+ today: PropTypes.string.isRequired,
86
+ todayButton: PropTypes.string,
87
+ week: PropTypes.string,
88
+ wrapper: PropTypes.string,
89
+ }),
90
+ className: PropTypes.string,
91
+ containerProps: PropTypes.object,
92
+ tabIndex: PropTypes.number,
93
+
94
+ // Custom elements
95
+ renderDay: PropTypes.func,
96
+ renderWeek: PropTypes.func,
97
+ weekdayElement: PropTypes.oneOfType([
98
+ PropTypes.element,
99
+ PropTypes.func,
100
+ PropTypes.instanceOf(Component),
101
+ ]),
102
+ navbarElement: PropTypes.oneOfType([
103
+ PropTypes.element,
104
+ PropTypes.func,
105
+ PropTypes.instanceOf(Component),
106
+ ]),
107
+ captionElement: PropTypes.oneOfType([
108
+ PropTypes.element,
109
+ PropTypes.func,
110
+ PropTypes.instanceOf(Component),
111
+ ]),
112
+
113
+ // Events
114
+ onBlur: PropTypes.func,
115
+ onFocus: PropTypes.func,
116
+ onKeyDown: PropTypes.func,
117
+ onDayClick: PropTypes.func,
118
+ onDayKeyDown: PropTypes.func,
119
+ onDayMouseEnter: PropTypes.func,
120
+ onDayMouseLeave: PropTypes.func,
121
+ onDayMouseDown: PropTypes.func,
122
+ onDayMouseUp: PropTypes.func,
123
+ onDayTouchStart: PropTypes.func,
124
+ onDayTouchEnd: PropTypes.func,
125
+ onDayFocus: PropTypes.func,
126
+ onMonthChange: PropTypes.func,
127
+ onCaptionClick: PropTypes.func,
128
+ onWeekClick: PropTypes.func,
129
+ onTodayButtonClick: PropTypes.func,
130
+ };
131
+
132
+ static defaultProps = {
133
+ classNames,
134
+ tabIndex: 0,
135
+ initialMonth: new Date(),
136
+ numberOfMonths: 1,
137
+ labels: {
138
+ previousMonth: 'Previous Month',
139
+ nextMonth: 'Next Month',
140
+ },
141
+ locale: 'en',
142
+ localeUtils: LocaleUtils,
143
+ showOutsideDays: false,
144
+ enableOutsideDaysClick: true,
145
+ fixedWeeks: false,
146
+ canChangeMonth: true,
147
+ reverseMonths: false,
148
+ pagedNavigation: false,
149
+ showWeekNumbers: false,
150
+ showWeekDays: true,
151
+ renderDay: (day) => day.getDate(),
152
+ renderWeek: (weekNumber) => weekNumber,
153
+ weekdayElement: <Weekday />,
154
+ navbarElement: <Navbar classNames={classNames} />,
155
+ captionElement: <Caption classNames={classNames} />,
156
+ };
157
+
158
+ constructor(props) {
159
+ super(props);
160
+
161
+ const currentMonth = this.getCurrentMonthFromProps(props);
162
+ this.state = {currentMonth};
163
+ }
164
+
165
+ componentDidUpdate(prevProps) {
166
+ // Changing the `month` props means changing the current displayed month
167
+ if (
168
+ prevProps.month !== this.props.month &&
169
+ !DateUtils.isSameMonth(prevProps.month, this.props.month)
170
+ ) {
171
+ const currentMonth = this.getCurrentMonthFromProps(this.props);
172
+ // eslint-disable-next-line react/no-did-update-set-state
173
+ this.setState({currentMonth});
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Return the month to be shown in the calendar based on the component props.
179
+ *
180
+ * @param {Object} props
181
+ * @returns Date
182
+ * @memberof DayPicker
183
+ * @private
184
+ */
185
+ getCurrentMonthFromProps(props) {
186
+ const initialMonth = Helpers.startOfMonth(
187
+ props.month || props.initialMonth
188
+ );
189
+ let currentMonth = initialMonth;
190
+
191
+ if (props.pagedNavigation && props.numberOfMonths > 1 && props.fromMonth) {
192
+ const diffInMonths = Helpers.getMonthsDiff(props.fromMonth, currentMonth);
193
+ currentMonth = DateUtils.addMonths(
194
+ props.fromMonth,
195
+ Math.floor(diffInMonths / props.numberOfMonths) * props.numberOfMonths
196
+ );
197
+ } else if (
198
+ props.toMonth &&
199
+ props.numberOfMonths > 1 &&
200
+ Helpers.getMonthsDiff(currentMonth, props.toMonth) <= 0
201
+ ) {
202
+ currentMonth = DateUtils.addMonths(
203
+ props.toMonth,
204
+ 1 - this.props.numberOfMonths
205
+ );
206
+ }
207
+ return currentMonth;
208
+ }
209
+
210
+ getNextNavigableMonth() {
211
+ return DateUtils.addMonths(
212
+ this.state.currentMonth,
213
+ this.props.numberOfMonths
214
+ );
215
+ }
216
+
217
+ getPreviousNavigableMonth() {
218
+ return DateUtils.addMonths(this.state.currentMonth, -1);
219
+ }
220
+
221
+ dayPicker = null;
222
+
223
+ allowPreviousMonth() {
224
+ const previousMonth = DateUtils.addMonths(this.state.currentMonth, -1);
225
+ return this.allowMonth(previousMonth);
226
+ }
227
+
228
+ allowNextMonth() {
229
+ const nextMonth = DateUtils.addMonths(
230
+ this.state.currentMonth,
231
+ this.props.numberOfMonths
232
+ );
233
+ return this.allowMonth(nextMonth);
234
+ }
235
+
236
+ allowMonth(d) {
237
+ const {fromMonth, toMonth, canChangeMonth} = this.props;
238
+ if (
239
+ !canChangeMonth ||
240
+ (fromMonth && Helpers.getMonthsDiff(fromMonth, d) < 0) ||
241
+ (toMonth && Helpers.getMonthsDiff(toMonth, d) > 0)
242
+ ) {
243
+ return false;
244
+ }
245
+ return true;
246
+ }
247
+
248
+ allowYearChange() {
249
+ return this.props.canChangeMonth;
250
+ }
251
+
252
+ showMonth(d, callback) {
253
+ if (!this.allowMonth(d)) {
254
+ return;
255
+ }
256
+ this.setState({currentMonth: Helpers.startOfMonth(d)}, () => {
257
+ if (callback) {
258
+ callback();
259
+ }
260
+ if (this.props.onMonthChange) {
261
+ this.props.onMonthChange(this.state.currentMonth);
262
+ }
263
+ });
264
+ }
265
+
266
+ showNextMonth = (callback) => {
267
+ if (!this.allowNextMonth()) {
268
+ return;
269
+ }
270
+ const deltaMonths = this.props.pagedNavigation
271
+ ? this.props.numberOfMonths
272
+ : 1;
273
+ const nextMonth = DateUtils.addMonths(this.state.currentMonth, deltaMonths);
274
+ this.showMonth(nextMonth, callback);
275
+ };
276
+
277
+ showPreviousMonth = (callback) => {
278
+ if (!this.allowPreviousMonth()) {
279
+ return;
280
+ }
281
+ const deltaMonths = this.props.pagedNavigation
282
+ ? this.props.numberOfMonths
283
+ : 1;
284
+ const previousMonth = DateUtils.addMonths(
285
+ this.state.currentMonth,
286
+ -deltaMonths
287
+ );
288
+ this.showMonth(previousMonth, callback);
289
+ };
290
+
291
+ showNextYear() {
292
+ if (!this.allowYearChange()) {
293
+ return;
294
+ }
295
+ const nextMonth = DateUtils.addMonths(this.state.currentMonth, 12);
296
+ this.showMonth(nextMonth);
297
+ }
298
+
299
+ showPreviousYear() {
300
+ if (!this.allowYearChange()) {
301
+ return;
302
+ }
303
+ const nextMonth = DateUtils.addMonths(this.state.currentMonth, -12);
304
+ this.showMonth(nextMonth);
305
+ }
306
+
307
+ focusFirstDayOfMonth() {
308
+ Helpers.getDayNodes(this.dayPicker, this.props.classNames)[0].focus();
309
+ }
310
+
311
+ focusLastDayOfMonth() {
312
+ const dayNodes = Helpers.getDayNodes(this.dayPicker, this.props.classNames);
313
+ dayNodes[dayNodes.length - 1].focus();
314
+ }
315
+
316
+ focusPreviousDay(dayNode) {
317
+ const dayNodes = Helpers.getDayNodes(this.dayPicker, this.props.classNames);
318
+ const dayNodeIndex = Helpers.nodeListToArray(dayNodes).indexOf(dayNode);
319
+ if (dayNodeIndex === -1) return;
320
+ if (dayNodeIndex === 0) {
321
+ this.showPreviousMonth(() => this.focusLastDayOfMonth());
322
+ } else {
323
+ dayNodes[dayNodeIndex - 1].focus();
324
+ }
325
+ }
326
+
327
+ focusNextDay(dayNode) {
328
+ const dayNodes = Helpers.getDayNodes(this.dayPicker, this.props.classNames);
329
+ const dayNodeIndex = Helpers.nodeListToArray(dayNodes).indexOf(dayNode);
330
+ if (dayNodeIndex === -1) return;
331
+ if (dayNodeIndex === dayNodes.length - 1) {
332
+ this.showNextMonth(() => this.focusFirstDayOfMonth());
333
+ } else {
334
+ dayNodes[dayNodeIndex + 1].focus();
335
+ }
336
+ }
337
+
338
+ focusNextWeek(dayNode) {
339
+ const dayNodes = Helpers.getDayNodes(this.dayPicker, this.props.classNames);
340
+ const dayNodeIndex = Helpers.nodeListToArray(dayNodes).indexOf(dayNode);
341
+ const isInLastWeekOfMonth = dayNodeIndex > dayNodes.length - 8;
342
+
343
+ if (isInLastWeekOfMonth) {
344
+ this.showNextMonth(() => {
345
+ const daysAfterIndex = dayNodes.length - dayNodeIndex;
346
+ const nextMonthDayNodeIndex = 7 - daysAfterIndex;
347
+ Helpers.getDayNodes(this.dayPicker, this.props.classNames)[
348
+ nextMonthDayNodeIndex
349
+ ].focus();
350
+ });
351
+ } else {
352
+ dayNodes[dayNodeIndex + 7].focus();
353
+ }
354
+ }
355
+
356
+ focusPreviousWeek(dayNode) {
357
+ const dayNodes = Helpers.getDayNodes(this.dayPicker, this.props.classNames);
358
+ const dayNodeIndex = Helpers.nodeListToArray(dayNodes).indexOf(dayNode);
359
+ const isInFirstWeekOfMonth = dayNodeIndex <= 6;
360
+
361
+ if (isInFirstWeekOfMonth) {
362
+ this.showPreviousMonth(() => {
363
+ const previousMonthDayNodes = Helpers.getDayNodes(
364
+ this.dayPicker,
365
+ this.props.classNames
366
+ );
367
+ const startOfLastWeekOfMonth = previousMonthDayNodes.length - 7;
368
+ const previousMonthDayNodeIndex = startOfLastWeekOfMonth + dayNodeIndex;
369
+ previousMonthDayNodes[previousMonthDayNodeIndex].focus();
370
+ });
371
+ } else {
372
+ dayNodes[dayNodeIndex - 7].focus();
373
+ }
374
+ }
375
+
376
+ // Event handlers
377
+
378
+ handleKeyDown = (e) => {
379
+ e.persist();
380
+
381
+ switch (e.keyCode) {
382
+ case LEFT:
383
+ this.showPreviousMonth();
384
+ break;
385
+ case RIGHT:
386
+ this.showNextMonth();
387
+ break;
388
+ case UP:
389
+ this.showPreviousYear();
390
+ break;
391
+ case DOWN:
392
+ this.showNextYear();
393
+ break;
394
+ default:
395
+ break;
396
+ }
397
+
398
+ if (this.props.onKeyDown) {
399
+ this.props.onKeyDown(e);
400
+ }
401
+ };
402
+
403
+ handleDayKeyDown = (day, modifiers, e) => {
404
+ e.persist();
405
+ switch (e.keyCode) {
406
+ case LEFT:
407
+ Helpers.cancelEvent(e);
408
+ this.focusPreviousDay(e.target);
409
+ break;
410
+ case RIGHT:
411
+ Helpers.cancelEvent(e);
412
+ this.focusNextDay(e.target);
413
+ break;
414
+ case UP:
415
+ Helpers.cancelEvent(e);
416
+ this.focusPreviousWeek(e.target);
417
+ break;
418
+ case DOWN:
419
+ Helpers.cancelEvent(e);
420
+ this.focusNextWeek(e.target);
421
+ break;
422
+ case ENTER:
423
+ case SPACE:
424
+ Helpers.cancelEvent(e);
425
+ if (this.props.onDayClick) {
426
+ this.handleDayClick(day, modifiers, e);
427
+ }
428
+ break;
429
+ default:
430
+ break;
431
+ }
432
+ if (this.props.onDayKeyDown) {
433
+ this.props.onDayKeyDown(day, modifiers, e);
434
+ }
435
+ };
436
+
437
+ handleDayClick = (day, modifiers, e) => {
438
+ e.persist();
439
+ if (
440
+ modifiers[this.props.classNames.outside] &&
441
+ this.props.enableOutsideDaysClick
442
+ ) {
443
+ this.handleOutsideDayClick(day);
444
+ }
445
+ if (this.props.onDayClick) {
446
+ this.props.onDayClick(day, modifiers, e);
447
+ }
448
+ };
449
+
450
+ handleOutsideDayClick(day) {
451
+ const {currentMonth} = this.state;
452
+ const {numberOfMonths} = this.props;
453
+ const diffInMonths = Helpers.getMonthsDiff(currentMonth, day);
454
+ if (diffInMonths > 0 && diffInMonths >= numberOfMonths) {
455
+ this.showNextMonth();
456
+ } else if (diffInMonths < 0) {
457
+ this.showPreviousMonth();
458
+ }
459
+ }
460
+
461
+ handleTodayButtonClick = (e) => {
462
+ const today = new Date();
463
+ const month = new Date(today.getFullYear(), today.getMonth());
464
+ this.showMonth(month);
465
+ e.target.blur();
466
+ if (this.props.onTodayButtonClick) {
467
+ e.persist();
468
+ this.props.onTodayButtonClick(
469
+ new Date(today.getFullYear(), today.getMonth(), today.getDate()),
470
+ ModifiersUtils.getModifiersForDay(today, this.props.modifiers),
471
+ e
472
+ );
473
+ }
474
+ };
475
+
476
+ renderNavbar() {
477
+ const {
478
+ labels,
479
+ locale,
480
+ localeUtils,
481
+ canChangeMonth,
482
+ navbarElement,
483
+ ...attributes
484
+ } = this.props;
485
+
486
+ if (!canChangeMonth) return null;
487
+
488
+ const props = {
489
+ month: this.state.currentMonth,
490
+ classNames: this.props.classNames,
491
+ className: this.props.classNames.navBar,
492
+ nextMonth: this.getNextNavigableMonth(),
493
+ previousMonth: this.getPreviousNavigableMonth(),
494
+ showPreviousButton: this.allowPreviousMonth(),
495
+ showNextButton: this.allowNextMonth(),
496
+ onNextClick: this.showNextMonth,
497
+ onPreviousClick: this.showPreviousMonth,
498
+ dir: attributes.dir,
499
+ labels,
500
+ locale,
501
+ localeUtils,
502
+ };
503
+ return React.isValidElement(navbarElement)
504
+ ? React.cloneElement(navbarElement, props)
505
+ : React.createElement(navbarElement, props);
506
+ }
507
+
508
+ renderMonths() {
509
+ const months = [];
510
+ const firstDayOfWeek = Helpers.getFirstDayOfWeekFromProps(this.props);
511
+ for (let i = 0; i < this.props.numberOfMonths; i += 1) {
512
+ const month = DateUtils.addMonths(this.state.currentMonth, i);
513
+ months.push(
514
+ <Month
515
+ key={i}
516
+ {...this.props}
517
+ month={month}
518
+ firstDayOfWeek={firstDayOfWeek}
519
+ onDayKeyDown={this.handleDayKeyDown}
520
+ onDayClick={this.handleDayClick}
521
+ />
522
+ );
523
+ }
524
+
525
+ if (this.props.reverseMonths) {
526
+ months.reverse();
527
+ }
528
+ return months;
529
+ }
530
+
531
+ renderFooter() {
532
+ if (this.props.todayButton) {
533
+ return (
534
+ <div className={this.props.classNames.footer}>
535
+ {this.renderTodayButton()}
536
+ </div>
537
+ );
538
+ }
539
+ return null;
540
+ }
541
+
542
+ renderTodayButton() {
543
+ return (
544
+ <button
545
+ type="button"
546
+ tabIndex={0}
547
+ className={this.props.classNames.todayButton}
548
+ aria-label={this.props.todayButton}
549
+ onClick={this.handleTodayButtonClick}
550
+ >
551
+ {this.props.todayButton}
552
+ </button>
553
+ );
554
+ }
555
+
556
+ render() {
557
+ let className = this.props.classNames.container;
558
+
559
+ if (!this.props.onDayClick) {
560
+ className = `${className} ${this.props.classNames.interactionDisabled}`;
561
+ }
562
+ if (this.props.className) {
563
+ className = `${className} ${this.props.className}`;
564
+ }
565
+ return (
566
+ <div
567
+ {...this.props.containerProps}
568
+ className={className}
569
+ ref={(el) => (this.dayPicker = el)}
570
+ lang={this.props.locale}
571
+ >
572
+ <div
573
+ className={this.props.classNames.wrapper}
574
+ tabIndex={
575
+ this.props.canChangeMonth &&
576
+ typeof this.props.tabIndex !== 'undefined'
577
+ ? this.props.tabIndex
578
+ : -1
579
+ }
580
+ onKeyDown={this.handleKeyDown}
581
+ onFocus={this.props.onFocus}
582
+ onBlur={this.props.onBlur}
583
+ >
584
+ {this.renderNavbar()}
585
+ <div className={this.props.classNames.months}>
586
+ {this.renderMonths()}
587
+ </div>
588
+ {this.renderFooter()}
589
+ </div>
590
+ </div>
591
+ );
592
+ }
593
+ }
594
+
595
+ DayPicker.DateUtils = DateUtils;
596
+ DayPicker.LocaleUtils = LocaleUtils;
597
+ DayPicker.ModifiersUtils = ModifiersUtils;
598
+
599
+ export {DateUtils, LocaleUtils, ModifiersUtils};
600
+
601
+ export default DayPicker;