Skip to content

Commit f26f53a

Browse files
committed
feat(ffe-datepicker-react): nytt format på datepicker
!!Breaking change: fjernet inputProps.
1 parent 2547231 commit f26f53a

File tree

13 files changed

+743
-392
lines changed

13 files changed

+743
-392
lines changed

packages/ffe-datepicker-react/src/datelogic/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ export type CalendarButtonState = {
77
isSelected: boolean;
88
isEnabled: boolean;
99
};
10+
11+
export type Locale = 'nb' | 'nn' | 'en';
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import React from 'react';
2-
import { Datepicker, DatepickerProps } from './Datepicker';
2+
import { Datepicker, DatepickerProviderProps } from './Datepicker';
33
import { render, screen } from '@testing-library/react';
44
import userEvent from '@testing-library/user-event';
55

66
const defaultProps = {
77
value: '',
88
onChange: () => {},
9+
locale: 'nb' as const,
910
};
1011

11-
const renderDatePicker = (props?: Partial<DatepickerProps>) =>
12+
const renderDatePicker = (props?: Partial<DatepickerProviderProps>) =>
1213
render(<Datepicker {...defaultProps} {...props} />);
1314

1415
describe('<Datepicker />', () => {
@@ -23,14 +24,40 @@ describe('<Datepicker />', () => {
2324

2425
it('contains a single DateInput component', () => {
2526
renderDatePicker();
26-
expect(screen.getByRole('textbox')).toBeInTheDocument();
27+
expect(screen.getByRole('group')).toBeInTheDocument();
2728
});
2829

2930
it('does not contain a Calendar component', () => {
3031
renderDatePicker();
3132
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
3233
});
3334

35+
it('responds to arrow up and down', async () => {
36+
renderDatePicker();
37+
const [dayInput] = screen.getAllByRole('spinbutton');
38+
await userEvent.type(dayInput, '{arrowup}');
39+
expect(dayInput).toHaveValue(1);
40+
await userEvent.type(dayInput, '{arrowdown}');
41+
expect(dayInput).toHaveValue(31);
42+
});
43+
44+
it('triggers onchange when arrows are used', async () => {
45+
const onChange = jest.fn();
46+
renderDatePicker({ onChange });
47+
const [dayInput] = screen.getAllByRole('spinbutton');
48+
await userEvent.type(dayInput, '{arrowup}');
49+
expect(onChange).toHaveBeenCalledTimes(1);
50+
});
51+
52+
it('reponds to arrow left and right', async () => {
53+
renderDatePicker();
54+
const [dayInput, monthInput] = screen.getAllByRole('spinbutton');
55+
await userEvent.type(dayInput, '{arrowright}');
56+
expect(monthInput).toHaveFocus();
57+
await userEvent.type(monthInput, '{arrowleft}');
58+
expect(dayInput).toHaveFocus();
59+
});
60+
3461
describe('with click on button', () => {
3562
const user = userEvent.setup();
3663
it('contains a Calendar', async () => {
@@ -54,8 +81,8 @@ describe('<Datepicker />', () => {
5481
it('calls onChange method', async () => {
5582
const onChange = jest.fn();
5683
renderDatePicker({ onChange });
57-
const input = screen.getByRole('textbox');
58-
await user.type(input, '1');
84+
const [dayInput] = screen.getAllByRole('spinbutton');
85+
await user.type(dayInput, '4');
5986
expect(onChange).toHaveBeenCalledTimes(1);
6087
});
6188
});
@@ -81,33 +108,24 @@ describe('<Datepicker />', () => {
81108
describe('ariaInvalid', () => {
82109
it('has correct aria-invalid value if given prop', () => {
83110
renderDatePicker({ ariaInvalid: true });
84-
const input = screen.getByRole('textbox');
85-
expect(input.getAttribute('aria-invalid')).toBe('true');
111+
const [date, month, year] =
112+
screen.getAllByRole('spinbutton');
113+
expect(date.getAttribute('aria-invalid')).toBe('true');
114+
expect(month.getAttribute('aria-invalid')).toBe('true');
115+
expect(year.getAttribute('aria-invalid')).toBe('true');
86116
});
87117

88118
it('has correct aria-describedby if aria-describedby given as input prop', () => {
89-
const inputProps = {
90-
'aria-describedby': 'test',
91-
};
92119
renderDatePicker({
93120
ariaInvalid: true,
94-
inputProps,
121+
ariaDescribedby: 'test',
95122
});
96-
const input = screen.getByRole('textbox');
97-
expect(input.getAttribute('aria-describedby')).toBe('test');
98-
});
99-
});
100123

101-
describe('inputProps', () => {
102-
it('is passed on to input field', () => {
103-
const inputProps = {
104-
className: 'customClass',
105-
id: 'custom-input-id',
106-
};
107-
renderDatePicker({ inputProps });
108-
const input = screen.getByRole('textbox');
109-
expect(input.classList.contains('customClass')).toBe(true);
110-
expect(input.getAttribute('id')).toBe('custom-input-id');
124+
const [date, month, year] =
125+
screen.getAllByRole('spinbutton');
126+
expect(date.getAttribute('aria-describedby')).toBe('test');
127+
expect(month.getAttribute('aria-describedby')).toBe('test');
128+
expect(year.getAttribute('aria-describedby')).toBe('test');
111129
});
112130
});
113131

@@ -126,43 +144,14 @@ describe('<Datepicker />', () => {
126144
});
127145
});
128146

129-
describe('try to be smart in which century to place an input of two digit years', () => {
130-
const user = userEvent.setup();
131-
it('defaults to the 20th century', async () => {
132-
const onChange = jest.fn();
133-
renderDatePicker({ onChange, value: '101099' });
134-
135-
const input = screen.getByRole('textbox');
136-
await user.type(input, '{Tab}');
137-
expect(onChange).toHaveBeenCalledWith('10.10.2099');
138-
});
139-
140-
it('assumes last century if maxDate is today-ish', async () => {
141-
const onChange = jest.fn();
142-
renderDatePicker({
143-
maxDate: '02.02.2022',
144-
onChange,
145-
value: '111199',
146-
});
147-
148-
const input = screen.getByRole('textbox');
149-
await user.type(input, '{Tab}');
150-
151-
expect(onChange).toHaveBeenCalledWith('11.11.1999');
152-
});
153-
154-
it('assumes this century if maxDate is today-ish but input is rather close to it', async () => {
155-
const onChange = jest.fn();
156-
renderDatePicker({
157-
maxDate: '02.02.2022',
158-
onChange,
159-
value: '121220',
160-
});
161-
162-
const input = screen.getByRole('textbox');
163-
await user.type(input, '{Tab}');
147+
describe('with value', () => {
148+
it('has correct value in input field', () => {
149+
renderDatePicker({ value: '01.01.2021' });
164150

165-
expect(onChange).toHaveBeenCalledWith('12.12.2020');
151+
const [date, month, year] = screen.getAllByRole('spinbutton');
152+
expect(date).toHaveValue(1);
153+
expect(month).toHaveValue(1);
154+
expect(year).toHaveValue(2021);
166155
});
167156
});
168157
});

packages/ffe-datepicker-react/src/datepicker/Datepicker.stories.tsx

+92-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useState } from 'react';
2-
import { Datepicker } from './Datepicker';
2+
import { Datepicker, DatepickerProviderProps } from './Datepicker';
33
import type { StoryObj, Meta } from '@storybook/react';
44
import { InputGroup } from '@sb1/ffe-form-react';
55

@@ -14,17 +14,103 @@ type Story = StoryObj<typeof Datepicker>;
1414
export const Standard: Story = {
1515
args: {
1616
locale: 'nb',
17-
maxDate: '31.12.2016',
18-
minDate: '01.01.2016',
17+
maxDate: '31.12.2025',
18+
minDate: '01.01.2024',
1919
},
20-
render: function Render({ value, onChange, ...args }) {
21-
const [date, setDate] = useState('01.01.2016');
20+
render: function Render({
21+
value,
22+
onChange,
23+
...args
24+
}: DatepickerProviderProps) {
25+
const [date, setDate] = useState('01.12.2024');
26+
27+
return (
28+
<InputGroup label="Dato">
29+
{inputProps => (
30+
<Datepicker
31+
value={value ?? date}
32+
onChange={setDate}
33+
{...inputProps}
34+
{...args}
35+
/>
36+
)}
37+
</InputGroup>
38+
);
39+
},
40+
};
41+
42+
export const FieldMessageString: Story = {
43+
args: {
44+
...Standard.args,
45+
},
46+
render: function Render({
47+
value,
48+
onChange,
49+
...args
50+
}: DatepickerProviderProps) {
51+
const [date, setDate] = useState('01.12.2024');
52+
53+
return (
54+
<InputGroup
55+
label="Dato"
56+
aria-invalid={true}
57+
fieldMessage={'Ugyldig dato'}
58+
>
59+
{inputProps => (
60+
<Datepicker
61+
value={value ?? date}
62+
onChange={setDate}
63+
{...inputProps}
64+
{...args}
65+
/>
66+
)}
67+
</InputGroup>
68+
);
69+
},
70+
};
71+
72+
export const FullWidth: Story = {
73+
args: {
74+
...Standard.args,
75+
fullWidth: true,
76+
},
77+
render: function Render({
78+
value,
79+
onChange,
80+
...args
81+
}: DatepickerProviderProps) {
82+
const [date, setDate] = useState('01.12.2024');
83+
2284
return (
2385
<InputGroup label="Dato">
2486
<Datepicker
87+
value={value ?? date}
88+
onChange={setDate}
2589
{...args}
90+
/>
91+
</InputGroup>
92+
);
93+
},
94+
};
95+
96+
export const CalendarAbove: Story = {
97+
args: {
98+
...Standard.args,
99+
calendarAbove: true,
100+
},
101+
render: function Render({
102+
value,
103+
onChange,
104+
...args
105+
}: DatepickerProviderProps) {
106+
const [date, setDate] = useState('01.12.2024');
107+
108+
return (
109+
<InputGroup label="Dato">
110+
<Datepicker
26111
value={value ?? date}
27-
onChange={onChange ?? setDate}
112+
onChange={setDate}
113+
{...args}
28114
/>
29115
</InputGroup>
30116
);

0 commit comments

Comments
 (0)