bright-components 10.1.0 → 10.2.1
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/components/Checkbox/index.js +6 -4
- package/dist/components/DayPicker/NewDayPicker/index.js +207 -0
- package/dist/components/DayPicker/index.js +30 -7
- package/dist/components/DayPickerPanel/index.js +1 -1
- package/dist/components/Modal/ModalBody/index.js +1 -0
- package/dist/components/Modal/index.js +2 -1
- package/dist/components/Time/TimePicker/index.js +1 -0
- package/dist/setupTests.js +5 -0
- package/package.json +3 -2
- package/src/components/Checkbox/index.js +2 -2
- package/src/components/DayPicker/NewDayPicker/index.js +208 -0
- package/src/components/DayPicker/examples.md +17 -0
- package/src/components/DayPicker/index.js +43 -17
- package/src/components/DayPicker/test.js +297 -1
- package/src/components/DayPickerPanel/index.js +1 -1
- package/src/components/DayPickerPanel/test.js +1 -1
- package/src/components/DurationInput/test.js +5 -3
- package/src/components/EmployeePicker/FilterBar/test.js +1 -1
- package/src/components/Modal/ModalBody/index.js +1 -0
- package/src/components/Modal/index.js +2 -1
- package/src/components/Modal/test.js +0 -1
- package/src/components/ResponsiveTabs/test.js +3 -3
- package/src/components/Time/TimePicker/index.js +1 -0
- package/src/components/Time/TimePicker/test.js +29 -28
- package/src/setupTests.js +2 -0
@@ -26,6 +26,8 @@ import breakpoints from 'constants/breakpoints';
|
|
26
26
|
|
27
27
|
import CalendarIcon from 'components/Icons/Calendar/';
|
28
28
|
|
29
|
+
import NewDayPicker from './NewDayPicker';
|
30
|
+
|
29
31
|
const friendlyShort = 'EEE dd MMM';
|
30
32
|
const friendlyShortWithYear = 'EEE dd MMM yyyy';
|
31
33
|
|
@@ -232,11 +234,12 @@ class DayPicker extends React.Component {
|
|
232
234
|
panelAbsoluteOnDesktop,
|
233
235
|
onSelectedDate,
|
234
236
|
isDateSelect,
|
237
|
+
typeable,
|
235
238
|
...rest
|
236
239
|
} = this.props;
|
237
240
|
|
238
241
|
const { dayPickerOpen } = this.state;
|
239
|
-
const { range } = this.props;
|
242
|
+
const { range, locale } = this.props;
|
240
243
|
|
241
244
|
const fromDate = range.from
|
242
245
|
? format(range.from, this.getDisplayFormat())
|
@@ -250,20 +253,39 @@ class DayPicker extends React.Component {
|
|
250
253
|
|
251
254
|
return (
|
252
255
|
<DayPickerInputContainer {...rest}>
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
256
|
+
{!typeable || dateRange ? (
|
257
|
+
<InputBox
|
258
|
+
onClick={this.toggleDayPicker}
|
259
|
+
error={error}
|
260
|
+
disabled={disabled}
|
261
|
+
legacyInputStyle={legacyInputStyle}
|
262
|
+
data-testid="input-selector"
|
263
|
+
>
|
264
|
+
{datesToDisplay ? (
|
265
|
+
<span>{datesToDisplay}</span>
|
266
|
+
) : (
|
267
|
+
<Placeholder>{placeholder}</Placeholder>
|
268
|
+
)}
|
269
|
+
<OpenCalendarIcon size={22} disabled={disabled} />
|
270
|
+
</InputBox>
|
271
|
+
) : (
|
272
|
+
<NewDayPicker
|
273
|
+
placeholder={placeholder}
|
274
|
+
datesToDisplay={datesToDisplay}
|
275
|
+
range={range}
|
276
|
+
allowClear={allowClear}
|
277
|
+
yearRange={yearRange}
|
278
|
+
onSelectedDate={onSelectedDate}
|
279
|
+
locale={locale}
|
280
|
+
clearValue={this.clearValue}
|
281
|
+
disabled={disabled}
|
282
|
+
error={error}
|
283
|
+
toggleDayPicker={this.toggleDayPicker}
|
284
|
+
GA={GA}
|
285
|
+
recordValue={recordValue}
|
286
|
+
dayPickerOpen={dayPickerOpen}
|
287
|
+
/>
|
288
|
+
)}
|
267
289
|
|
268
290
|
{dayPickerOpen && (
|
269
291
|
<DayRangeContainer
|
@@ -330,7 +352,9 @@ DayPicker.propTypes = {
|
|
330
352
|
legacyInputStyle: bool,
|
331
353
|
closeButton: bool,
|
332
354
|
panelAbsoluteOnDesktop: bool,
|
333
|
-
isDateSelect: bool
|
355
|
+
isDateSelect: bool,
|
356
|
+
typeable: bool,
|
357
|
+
locale: string
|
334
358
|
};
|
335
359
|
|
336
360
|
DayPicker.defaultProps = {
|
@@ -356,7 +380,9 @@ DayPicker.defaultProps = {
|
|
356
380
|
legacyInputStyle: false,
|
357
381
|
closeButton: false,
|
358
382
|
panelAbsoluteOnDesktop: true,
|
359
|
-
isDateSelect: false
|
383
|
+
isDateSelect: false,
|
384
|
+
typeable: false,
|
385
|
+
locale: 'GB'
|
360
386
|
};
|
361
387
|
|
362
388
|
export { DayPicker as Unwrapped };
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { render, fireEvent } from '@testing-library/react';
|
2
|
+
import { render, fireEvent, wait } from '@testing-library/react';
|
3
|
+
import userEvent from '@testing-library/user-event';
|
3
4
|
import ReactGA from 'react-ga';
|
4
5
|
import DayPicker from '.';
|
5
6
|
|
@@ -406,4 +407,299 @@ describe('<DayPicker />', () => {
|
|
406
407
|
expect(ReactGA.event).toHaveBeenCalledTimes(1);
|
407
408
|
});
|
408
409
|
});
|
410
|
+
|
411
|
+
describe('Typing date', () => {
|
412
|
+
it('should set the correct date when typed in', async () => {
|
413
|
+
wrapper.rerender(
|
414
|
+
<DayPicker
|
415
|
+
{...props}
|
416
|
+
typeable
|
417
|
+
dateRange={false}
|
418
|
+
yearRange={{ min: 2000, max: 2100 }}
|
419
|
+
GA={{
|
420
|
+
category: undefined,
|
421
|
+
actionId: undefined
|
422
|
+
}}
|
423
|
+
/>
|
424
|
+
);
|
425
|
+
const inputSelect = wrapper.getByTestId('new input');
|
426
|
+
|
427
|
+
fireEvent.focus(inputSelect);
|
428
|
+
userEvent.type(inputSelect, `010203`);
|
429
|
+
await wait(() => expect(inputSelect.value).toEqual('01/02/03'));
|
430
|
+
fireEvent.blur(inputSelect);
|
431
|
+
|
432
|
+
expect(onMockSelectedDate).toHaveBeenLastCalledWith({
|
433
|
+
from: new Date('2003-02-01T00:00:00.000Z'),
|
434
|
+
to: new Date('2003-02-01T00:00:00.000Z')
|
435
|
+
});
|
436
|
+
});
|
437
|
+
|
438
|
+
it('should set the correct date when typed in - CA', () => {
|
439
|
+
wrapper.rerender(
|
440
|
+
<DayPicker
|
441
|
+
{...props}
|
442
|
+
typeable
|
443
|
+
dateRange={false}
|
444
|
+
yearRange={{ min: 2000, max: 2100 }}
|
445
|
+
locale="CA"
|
446
|
+
/>
|
447
|
+
);
|
448
|
+
const inputSelect = wrapper.getByTestId('new input');
|
449
|
+
|
450
|
+
fireEvent.focus(inputSelect);
|
451
|
+
userEvent.type(inputSelect, '010203');
|
452
|
+
fireEvent.blur(inputSelect);
|
453
|
+
|
454
|
+
expect(onMockSelectedDate).toHaveBeenLastCalledWith({
|
455
|
+
from: new Date('2001-02-03T00:00:00.000Z'),
|
456
|
+
to: new Date('2001-02-03T00:00:00.000Z')
|
457
|
+
});
|
458
|
+
});
|
459
|
+
|
460
|
+
it('should show the correct date when date pre set', () => {
|
461
|
+
wrapper.rerender(
|
462
|
+
<DayPicker
|
463
|
+
{...props}
|
464
|
+
typeable
|
465
|
+
dateRange={false}
|
466
|
+
yearRange={{ min: 2000, max: 2100 }}
|
467
|
+
range={{
|
468
|
+
from: new Date('2019-08-01'),
|
469
|
+
to: undefined
|
470
|
+
}}
|
471
|
+
/>
|
472
|
+
);
|
473
|
+
const inputSelect = wrapper.getByTestId('new input');
|
474
|
+
|
475
|
+
fireEvent.focus(inputSelect);
|
476
|
+
|
477
|
+
expect(inputSelect.value).toEqual('01/08/19');
|
478
|
+
});
|
479
|
+
|
480
|
+
it('should show the correct date when date pre set - CA', () => {
|
481
|
+
wrapper.rerender(
|
482
|
+
<DayPicker
|
483
|
+
{...props}
|
484
|
+
typeable
|
485
|
+
dateRange={false}
|
486
|
+
yearRange={{ min: 2000, max: 2100 }}
|
487
|
+
range={{
|
488
|
+
from: new Date('2019-08-01'),
|
489
|
+
to: undefined
|
490
|
+
}}
|
491
|
+
locale="CA"
|
492
|
+
/>
|
493
|
+
);
|
494
|
+
const inputSelect = wrapper.getByTestId('new input');
|
495
|
+
|
496
|
+
fireEvent.focus(inputSelect);
|
497
|
+
|
498
|
+
expect(inputSelect.value).toEqual('19/08/01');
|
499
|
+
});
|
500
|
+
|
501
|
+
it('should allow clearing date', () => {
|
502
|
+
wrapper.rerender(
|
503
|
+
<DayPicker
|
504
|
+
{...props}
|
505
|
+
typeable
|
506
|
+
dateRange={false}
|
507
|
+
yearRange={{ min: 2000, max: 2100 }}
|
508
|
+
range={{
|
509
|
+
from: new Date('2019-08-01'),
|
510
|
+
to: undefined
|
511
|
+
}}
|
512
|
+
/>
|
513
|
+
);
|
514
|
+
const inputSelect = wrapper.getByTestId('new input');
|
515
|
+
|
516
|
+
fireEvent.focus(inputSelect);
|
517
|
+
userEvent.type(inputSelect, '{selectall}{backspace}');
|
518
|
+
fireEvent.blur(inputSelect);
|
519
|
+
|
520
|
+
expect(onMockSelectedDate).toHaveBeenLastCalledWith({
|
521
|
+
from: undefined,
|
522
|
+
to: undefined
|
523
|
+
});
|
524
|
+
});
|
525
|
+
|
526
|
+
it('shouldnt save invalid dates', () => {
|
527
|
+
wrapper.rerender(
|
528
|
+
<DayPicker
|
529
|
+
{...props}
|
530
|
+
typeable
|
531
|
+
dateRange={false}
|
532
|
+
yearRange={{ min: 2000, max: 2100 }}
|
533
|
+
range={{
|
534
|
+
from: new Date('2019-08-01'),
|
535
|
+
to: undefined
|
536
|
+
}}
|
537
|
+
/>
|
538
|
+
);
|
539
|
+
const inputSelect = wrapper.getByTestId('new input');
|
540
|
+
|
541
|
+
fireEvent.focus(inputSelect);
|
542
|
+
fireEvent.blur(inputSelect);
|
543
|
+
fireEvent.focus(inputSelect);
|
544
|
+
userEvent.type(inputSelect, '{selectall}{backspace}0101');
|
545
|
+
fireEvent.blur(inputSelect);
|
546
|
+
|
547
|
+
expect(onMockSelectedDate).toHaveBeenLastCalledWith('');
|
548
|
+
expect(wrapper.getByText('Date is invalid')).toBeInTheDocument();
|
549
|
+
});
|
550
|
+
|
551
|
+
it('shouldnt save dates outside the range', () => {
|
552
|
+
wrapper.rerender(
|
553
|
+
<DayPicker
|
554
|
+
{...props}
|
555
|
+
typeable
|
556
|
+
dateRange={false}
|
557
|
+
yearRange={{ min: 2018, max: 2030 }}
|
558
|
+
range={{
|
559
|
+
from: new Date('2019-08-01'),
|
560
|
+
to: undefined
|
561
|
+
}}
|
562
|
+
allowClear={false}
|
563
|
+
/>
|
564
|
+
);
|
565
|
+
const inputSelect = wrapper.getByTestId('new input');
|
566
|
+
|
567
|
+
fireEvent.focus(inputSelect);
|
568
|
+
userEvent.type(inputSelect, '{selectall}{backspace}010131');
|
569
|
+
fireEvent.blur(inputSelect);
|
570
|
+
|
571
|
+
expect(onMockSelectedDate).toHaveBeenLastCalledWith({
|
572
|
+
from: new Date('2019-08-01T00:00:00.000Z'),
|
573
|
+
to: undefined
|
574
|
+
});
|
575
|
+
expect(
|
576
|
+
wrapper.getByText(
|
577
|
+
'Year is outside of range. Must be between 2018 - 2030'
|
578
|
+
)
|
579
|
+
).toBeInTheDocument();
|
580
|
+
});
|
581
|
+
|
582
|
+
it('should revert invalid date to empty if no initial date', () => {
|
583
|
+
onMockSelectedDate.mockClear();
|
584
|
+
wrapper.rerender(
|
585
|
+
<DayPicker
|
586
|
+
{...props}
|
587
|
+
typeable
|
588
|
+
dateRange={false}
|
589
|
+
yearRange={{ min: 2000, max: 2100 }}
|
590
|
+
range={{
|
591
|
+
from: undefined,
|
592
|
+
to: undefined
|
593
|
+
}}
|
594
|
+
allowClear={false}
|
595
|
+
/>
|
596
|
+
);
|
597
|
+
const inputSelect = wrapper.getByTestId('new input');
|
598
|
+
|
599
|
+
fireEvent.focus(inputSelect);
|
600
|
+
fireEvent.blur(inputSelect);
|
601
|
+
fireEvent.focus(inputSelect);
|
602
|
+
userEvent.type(inputSelect, '{selectall}{backspace}0101');
|
603
|
+
fireEvent.blur(inputSelect);
|
604
|
+
|
605
|
+
expect(onMockSelectedDate).not.toHaveBeenCalled();
|
606
|
+
});
|
607
|
+
|
608
|
+
it('backspace / automatically', () => {
|
609
|
+
wrapper.rerender(
|
610
|
+
<DayPicker
|
611
|
+
{...props}
|
612
|
+
typeable
|
613
|
+
dateRange={false}
|
614
|
+
yearRange={{ min: 2000, max: 2100 }}
|
615
|
+
range={{
|
616
|
+
from: new Date('2019-08-01'),
|
617
|
+
to: undefined
|
618
|
+
}}
|
619
|
+
/>
|
620
|
+
);
|
621
|
+
const inputSelect = wrapper.getByTestId('new input');
|
622
|
+
|
623
|
+
fireEvent.focus(inputSelect);
|
624
|
+
userEvent.type(inputSelect, `{backspace}{backspace}/`);
|
625
|
+
expect(inputSelect.value).toEqual('01/08/');
|
626
|
+
});
|
627
|
+
|
628
|
+
it('should open calendar view with the icon', () => {
|
629
|
+
wrapper.rerender(
|
630
|
+
<DayPicker
|
631
|
+
{...props}
|
632
|
+
typeable
|
633
|
+
dateRange={false}
|
634
|
+
yearRange={{ min: 2000, max: 2100 }}
|
635
|
+
range={{
|
636
|
+
from: new Date('2019-08-01'),
|
637
|
+
to: undefined
|
638
|
+
}}
|
639
|
+
/>
|
640
|
+
);
|
641
|
+
|
642
|
+
fireEvent.click(wrapper.getByTestId('calendarIcon'));
|
643
|
+
expect(wrapper.getByTestId('daypicker-panel')).toBeInTheDocument();
|
644
|
+
|
645
|
+
const inputSelect = wrapper.getByTestId('new input');
|
646
|
+
fireEvent.focus(inputSelect);
|
647
|
+
fireEvent.blur(inputSelect);
|
648
|
+
|
649
|
+
expect(
|
650
|
+
wrapper.queryByTestId('daypicker-panel')
|
651
|
+
).not.toBeInTheDocument();
|
652
|
+
});
|
653
|
+
|
654
|
+
it('should apply the error styling if error', () => {
|
655
|
+
wrapper.rerender(
|
656
|
+
<DayPicker {...props} dateRange={false} typeable error />
|
657
|
+
);
|
658
|
+
|
659
|
+
const inputSelect = wrapper.getByTestId('input-selector');
|
660
|
+
expect(inputSelect).toHaveStyleRule(
|
661
|
+
'border-color',
|
662
|
+
'#FF5000 !important'
|
663
|
+
);
|
664
|
+
});
|
665
|
+
|
666
|
+
it('should apply the error styling if disabled', () => {
|
667
|
+
wrapper.rerender(
|
668
|
+
<DayPicker {...props} typeable dateRange={false} disabled />
|
669
|
+
);
|
670
|
+
|
671
|
+
const inputSelect = wrapper.getByTestId('new input');
|
672
|
+
expect(inputSelect).toBeDisabled();
|
673
|
+
});
|
674
|
+
|
675
|
+
it('should call the correct GA tags when the date is typed', async () => {
|
676
|
+
wrapper.rerender(
|
677
|
+
<DayPicker
|
678
|
+
{...props}
|
679
|
+
typeable
|
680
|
+
dateRange={false}
|
681
|
+
range={{
|
682
|
+
from: undefined,
|
683
|
+
to: undefined
|
684
|
+
}}
|
685
|
+
recordValue
|
686
|
+
/>
|
687
|
+
);
|
688
|
+
expect(ReactGA.event).toHaveBeenCalledTimes(0);
|
689
|
+
|
690
|
+
const inputSelect = wrapper.getByTestId('new input');
|
691
|
+
fireEvent.focus(inputSelect);
|
692
|
+
userEvent.type(inputSelect, `201222`);
|
693
|
+
await wait(() => expect(inputSelect.value).toEqual('20/12/22'));
|
694
|
+
fireEvent.blur(inputSelect);
|
695
|
+
|
696
|
+
await wait(() =>
|
697
|
+
expect(ReactGA.event).toHaveBeenCalledWith({
|
698
|
+
action: 'ActionID - Set via Typing',
|
699
|
+
category: 'Test',
|
700
|
+
label: 'Tue 20 Dec 2022'
|
701
|
+
})
|
702
|
+
);
|
703
|
+
});
|
704
|
+
});
|
409
705
|
});
|
@@ -178,7 +178,7 @@ class DayPickerPanel extends React.Component {
|
|
178
178
|
range: { from, to }
|
179
179
|
} = this.state;
|
180
180
|
|
181
|
-
const actionEvent = selectedDay ? 'Set' : 'Apply';
|
181
|
+
const actionEvent = selectedDay ? 'Set via Date Picker' : 'Apply';
|
182
182
|
|
183
183
|
if (category) {
|
184
184
|
const label = dateRange
|
@@ -20,7 +20,7 @@ describe('<DurationInput />', () => {
|
|
20
20
|
});
|
21
21
|
|
22
22
|
it('should select a new days value when the days input is changed', () => {
|
23
|
-
const daysInput = wrapper.getByRole('
|
23
|
+
const daysInput = wrapper.getByRole('spinbutton');
|
24
24
|
|
25
25
|
expect(onChange).not.toHaveBeenCalled();
|
26
26
|
|
@@ -36,7 +36,7 @@ describe('<DurationInput />', () => {
|
|
36
36
|
const blurProps = { ...props, onBlur: jest.fn() };
|
37
37
|
wrapper.rerender(<DurationInput {...blurProps} />);
|
38
38
|
|
39
|
-
const daysInput = wrapper.getByRole('
|
39
|
+
const daysInput = wrapper.getByRole('spinbutton');
|
40
40
|
fireEvent.blur(daysInput);
|
41
41
|
|
42
42
|
expect(blurProps.onBlur).toHaveBeenCalled();
|
@@ -54,7 +54,9 @@ describe('<DurationInput />', () => {
|
|
54
54
|
});
|
55
55
|
|
56
56
|
it('should select a new hours value and a new minutes value when the inputs are changed', () => {
|
57
|
-
const [hoursInput, minutesInput] = wrapper.getAllByRole(
|
57
|
+
const [hoursInput, minutesInput] = wrapper.getAllByRole(
|
58
|
+
'spinbutton'
|
59
|
+
);
|
58
60
|
|
59
61
|
expect(onChange).not.toHaveBeenCalled();
|
60
62
|
|
@@ -33,7 +33,7 @@ describe('EmployeePickerFilterBar', () => {
|
|
33
33
|
});
|
34
34
|
|
35
35
|
const getInput = () => element.getByPlaceholderText('Enter name');
|
36
|
-
const getSelect = () => element.getByRole('
|
36
|
+
const getSelect = () => element.getByRole('combobox');
|
37
37
|
|
38
38
|
it('should call updateType when the user selects a filter type', () => {
|
39
39
|
const input = getInput();
|
@@ -34,6 +34,8 @@ const Background = styled.div`
|
|
34
34
|
`;
|
35
35
|
|
36
36
|
const ModalContainer = styled.div`
|
37
|
+
display: flex;
|
38
|
+
flex-direction: column;
|
37
39
|
background: white;
|
38
40
|
position: relative;
|
39
41
|
width: ${props => props.width};
|
@@ -43,7 +45,6 @@ const ModalContainer = styled.div`
|
|
43
45
|
border-radius: ${vars.borderRadius};
|
44
46
|
max-height: 90%;
|
45
47
|
overflow-x: hidden;
|
46
|
-
overflow-y: auto;
|
47
48
|
${props => props.version === '1' && '-webkit-overflow-scrolling: touch'};
|
48
49
|
|
49
50
|
${props =>
|
@@ -133,7 +133,6 @@ describe('<Modal />', () => {
|
|
133
133
|
const modalContainer = wrapper.getByRole('region');
|
134
134
|
|
135
135
|
expect(modalContainer).toHaveStyleRule('overflow-x', 'hidden');
|
136
|
-
expect(modalContainer).toHaveStyleRule('overflow-y', 'auto');
|
137
136
|
|
138
137
|
wrapper.rerender(
|
139
138
|
<Modal close={closeFn} allowOverflow>
|
@@ -15,7 +15,7 @@ describe('<ResponsiveTabs />', () => {
|
|
15
15
|
</ResponsiveTabs>
|
16
16
|
);
|
17
17
|
|
18
|
-
expect(getByRole('
|
18
|
+
expect(getByRole('combobox')).toBeInTheDocument();
|
19
19
|
expect(getAllByRole('option')).toHaveLength(2);
|
20
20
|
});
|
21
21
|
|
@@ -38,7 +38,7 @@ describe('<ResponsiveTabs />', () => {
|
|
38
38
|
expect(getByTestId('tab1')).toBeVisible();
|
39
39
|
expect(getByTestId('tab2')).not.toBeVisible();
|
40
40
|
|
41
|
-
const dropdown = getByRole('
|
41
|
+
const dropdown = getByRole('combobox');
|
42
42
|
fireEvent.change(dropdown, { target: { value: 'Two' } });
|
43
43
|
|
44
44
|
expect(getByTestId('tab1')).not.toBeVisible();
|
@@ -90,7 +90,7 @@ describe('<ResponsiveTabs />', () => {
|
|
90
90
|
</ResponsiveTabs>
|
91
91
|
);
|
92
92
|
|
93
|
-
fireEvent.change(getByRole('
|
93
|
+
fireEvent.change(getByRole('combobox'), { target: { value: 'One' } });
|
94
94
|
expect(event).not.toHaveBeenCalled();
|
95
95
|
|
96
96
|
fireEvent.click(getByRole('tab'));
|