bright-components 10.1.0 → 10.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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'));
|