@hyphen/hyphen-components 7.10.0 → 8.0.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/css/fonts.css +5 -3
- package/dist/css/fonts.css.map +1 -0
- package/dist/css/index.css +370 -222
- package/dist/css/index.css.map +1 -0
- package/dist/css/reset.css +5 -3
- package/dist/css/reset.css.map +1 -0
- package/dist/css/utilities.css +487 -43
- package/dist/css/utilities.css.map +1 -0
- package/dist/css/variables.css +180 -33
- package/dist/css/variables.css.map +1 -0
- package/dist/hyphen-components.cjs.development.js +250 -317
- package/dist/hyphen-components.cjs.development.js.map +1 -1
- package/dist/hyphen-components.cjs.production.min.js +2 -2
- package/dist/hyphen-components.cjs.production.min.js.map +1 -1
- package/dist/hyphen-components.esm.js +204 -271
- package/dist/hyphen-components.esm.js.map +1 -1
- package/dist/index.d.ts +25 -60
- package/package.json +4 -4
- package/src/components/Alert/Alert.mdx +1 -1
- package/src/components/Alert/Alert.module.scss +29 -34
- package/src/components/Alert/Alert.stories.tsx +11 -3
- package/src/components/Alert/Alert.test.tsx +17 -11
- package/src/components/Alert/Alert.tsx +9 -16
- package/src/components/Badge/Badge.mdx +46 -4
- package/src/components/Badge/Badge.module.scss +235 -185
- package/src/components/Badge/Badge.stories.tsx +126 -36
- package/src/components/Badge/Badge.test.tsx +180 -21
- package/src/components/Badge/Badge.tsx +56 -21
- package/src/components/Button/Button.module.scss +1 -1
- package/src/components/CheckboxInput/components/Checkbox.module.scss +2 -2
- package/src/components/Drawer/Drawer.mdx +14 -16
- package/src/components/Drawer/Drawer.module.scss +1 -1
- package/src/components/DropdownMenu/DropdownMenu.tsx +6 -8
- package/src/components/Formik/Formik.stories.tsx +3 -5
- package/src/components/Formik/FormikTimePicker/FormikTimePicker.test.tsx +34 -67
- package/src/components/Formik/FormikTimePicker/FormikTimePicker.tsx +0 -2
- package/src/components/Modal/Modal.module.scss +1 -1
- package/src/components/RadioGroup/RadioInput/RadioInput.module.scss +2 -2
- package/src/components/SelectInput/SelectInput.module.scss +1 -1
- package/src/components/SelectInputInset/SelectInputInset.module.scss +1 -1
- package/src/components/SelectInputNative/SelectInputNative.module.scss +1 -1
- package/src/components/Switch/Switch.module.scss +1 -1
- package/src/components/Table/Table.stories.tsx +4 -4
- package/src/components/TextInput/TextInput.module.scss +1 -1
- package/src/components/TextInputInset/TextInputInset.module.scss +1 -1
- package/src/components/TextareaInput/TextareaInput.module.scss +1 -1
- package/src/components/TextareaInputInset/TextareaInputInset.module.scss +1 -1
- package/src/components/TimePicker/TimePicker.mdx +3 -11
- package/src/components/TimePicker/TimePicker.stories.tsx +61 -60
- package/src/components/TimePicker/TimePicker.test.tsx +76 -7
- package/src/components/TimePicker/TimePicker.tsx +37 -7
- package/src/components/Toggle/Toggle.module.scss +1 -1
- package/src/components/ToggleGroup/ToggleGroup.module.scss +1 -1
- package/src/components/Tooltip/Tooltip.stories.tsx +1 -1
- package/src/docs/Colors.mdx +13 -0
- package/src/index.ts +0 -2
- package/src/styles/display.scss +1 -1
- package/src/styles/flex.scss +1 -1
- package/src/styles/overflow.scss +2 -0
- package/src/styles/position.scss +2 -0
- package/src/styles/text-align.scss +2 -0
- package/src/styles/utilities.scss +10 -9
- package/src/styles/variables/index.scss +2 -1
- package/src/styles/white-space.scss +2 -0
- package/src/components/Formik/FormikTimePickerNative/FormikTimePickerNative.test.tsx +0 -175
- package/src/components/Formik/FormikTimePickerNative/FormikTimePickerNative.tsx +0 -38
- package/src/components/TimePickerNative/TimePickerNative.mdx +0 -67
- package/src/components/TimePickerNative/TimePickerNative.stories.tsx +0 -150
- package/src/components/TimePickerNative/TimePickerNative.test.tsx +0 -117
- package/src/components/TimePickerNative/TimePickerNative.tsx +0 -93
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { render, fireEvent, screen, waitFor } from '@testing-library/react';
|
|
3
|
-
import selectEvent from 'react-select-event';
|
|
4
3
|
import { Formik, Form, Field, FormikValues, getIn, setIn } from 'formik';
|
|
5
4
|
import { FormikTimePicker } from './FormikTimePicker';
|
|
6
5
|
|
|
7
6
|
const testLabelName = 'test select';
|
|
8
7
|
|
|
9
|
-
type Option = { value: string; label: string };
|
|
10
8
|
const handleValidation = (testValueKey: string) => (values: FormikValues) =>
|
|
11
9
|
getIn(values, testValueKey)?.length > 1
|
|
12
10
|
? {}
|
|
@@ -17,10 +15,9 @@ const renderForm = (
|
|
|
17
15
|
props: {
|
|
18
16
|
placeholder?: string;
|
|
19
17
|
hideLabel?: boolean;
|
|
20
|
-
isMulti?: boolean;
|
|
21
18
|
isRequired?: unknown;
|
|
22
19
|
isDisabled?: boolean;
|
|
23
|
-
onChange?: jest.Mock<void, [
|
|
20
|
+
onChange?: jest.Mock<void, [React.ChangeEvent<HTMLSelectElement>]>; // eslint-disable-line
|
|
24
21
|
interval?: number;
|
|
25
22
|
},
|
|
26
23
|
testValueKey = testLabelName
|
|
@@ -33,7 +30,7 @@ const renderForm = (
|
|
|
33
30
|
onSubmit={() => {}} // eslint-disable-line
|
|
34
31
|
>
|
|
35
32
|
{() => (
|
|
36
|
-
<Form>
|
|
33
|
+
<Form noValidate>
|
|
37
34
|
<Field
|
|
38
35
|
label={testValueKey}
|
|
39
36
|
name={testValueKey}
|
|
@@ -93,62 +90,39 @@ describe('FormikTimePicker', () => {
|
|
|
93
90
|
|
|
94
91
|
describe('Single select, pre-selected', () => {
|
|
95
92
|
test('it renders with value pre-selected', () => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
{}
|
|
100
|
-
)
|
|
101
|
-
);
|
|
93
|
+
const initialValue = new Date(2020, 0, 1, 0, 0, 0, 120).toISOString();
|
|
94
|
+
const expectedValue = new Date();
|
|
95
|
+
expectedValue.setHours(0, 0, 0, 0);
|
|
102
96
|
|
|
103
|
-
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
describe('Multi select, no selection', () => {
|
|
108
|
-
test('it renders input with a label, and with a default placeholder', () => {
|
|
109
|
-
render(renderForm(undefined, { isMulti: true }));
|
|
97
|
+
render(renderForm(initialValue, {}));
|
|
110
98
|
|
|
111
|
-
expect(screen.getByLabelText(testLabelName)).
|
|
112
|
-
|
|
99
|
+
expect(screen.getByLabelText(testLabelName)).toHaveValue(
|
|
100
|
+
expectedValue.toISOString()
|
|
101
|
+
);
|
|
113
102
|
});
|
|
114
103
|
});
|
|
115
104
|
|
|
116
|
-
describe('
|
|
117
|
-
test('it
|
|
118
|
-
render(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
{ label: '12:00 AM', value: '2020-10-23T04:30:00.120Z' },
|
|
122
|
-
{ label: '12:15 AM', value: '2020-10-23T04:45:00.120Z' },
|
|
123
|
-
],
|
|
124
|
-
{ isMulti: true }
|
|
125
|
-
)
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
expect(screen.getByLabelText(testLabelName)).toBeInTheDocument();
|
|
129
|
-
expect(screen.queryByText('HH:MM')).toBeNull();
|
|
130
|
-
expect(screen.getByText('12:00 AM')).toBeInTheDocument();
|
|
131
|
-
expect(screen.getByText('12:15 AM')).toBeInTheDocument();
|
|
105
|
+
describe('Is Required', () => {
|
|
106
|
+
test('it sets aria-required on the input', () => {
|
|
107
|
+
render(renderForm(undefined, { isRequired: true }));
|
|
108
|
+
const inputElement = screen.getByLabelText(testLabelName);
|
|
109
|
+
expect(inputElement).toHaveAttribute('aria-required', 'true');
|
|
132
110
|
});
|
|
133
111
|
});
|
|
134
112
|
|
|
135
113
|
describe('Is Disabled', () => {
|
|
136
114
|
test('it disables the input', () => {
|
|
137
|
-
|
|
138
|
-
renderForm(undefined, { isDisabled: true })
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
const disabledInput = container.querySelector(
|
|
142
|
-
'.react-select__control[aria-disabled="true"]'
|
|
143
|
-
);
|
|
115
|
+
render(renderForm(undefined, { isDisabled: true }));
|
|
144
116
|
|
|
145
|
-
expect(
|
|
117
|
+
expect(screen.getByLabelText(testLabelName)).toBeDisabled();
|
|
146
118
|
});
|
|
147
119
|
});
|
|
148
120
|
|
|
149
121
|
describe('Is Invalid, with a helpful message', () => {
|
|
150
122
|
test('it renders the helpful message', async () => {
|
|
151
|
-
const { getByText } = render(
|
|
123
|
+
const { getByText } = render(
|
|
124
|
+
renderForm(undefined, { isRequired: true })
|
|
125
|
+
);
|
|
152
126
|
const submitButton = getByText('submit');
|
|
153
127
|
|
|
154
128
|
fireEvent.click(submitButton);
|
|
@@ -178,34 +152,17 @@ describe('FormikTimePicker', () => {
|
|
|
178
152
|
describe('Callback Handling', () => {
|
|
179
153
|
describe('onChange', () => {
|
|
180
154
|
test("Custom onChange event fires callback function, overwriting Formik's onChange", async () => {
|
|
181
|
-
let value:
|
|
155
|
+
let value: string | undefined;
|
|
182
156
|
const mockedHandleChange = jest.fn((event) => {
|
|
183
|
-
|
|
157
|
+
event.persist();
|
|
184
158
|
});
|
|
185
159
|
|
|
186
|
-
const { getByLabelText
|
|
160
|
+
const { getByLabelText } = render(
|
|
187
161
|
renderForm(value, { onChange: mockedHandleChange })
|
|
188
162
|
);
|
|
189
163
|
const selectInput = getByLabelText(testLabelName);
|
|
190
|
-
|
|
191
|
-
* This class is specific to react-select, combined with our custom classNamePrefix prop.
|
|
192
|
-
* While this is an implementation detail there appears to be
|
|
193
|
-
* no clearer path to test our own component which depends on react-select
|
|
194
|
-
*/
|
|
195
|
-
const selectInputWrapper = container.querySelector(
|
|
196
|
-
'.react-select__control'
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
fireEvent.focus(selectInput);
|
|
200
|
-
if (selectInputWrapper) {
|
|
201
|
-
fireEvent.mouseDown(selectInputWrapper);
|
|
202
|
-
}
|
|
203
|
-
const option = await waitFor(() => getByText('12:00 AM'), {
|
|
204
|
-
container,
|
|
205
|
-
});
|
|
206
|
-
fireEvent.click(option);
|
|
164
|
+
fireEvent.change(selectInput, { target: { value: 'hello' } });
|
|
207
165
|
expect(mockedHandleChange).toHaveBeenCalledTimes(1);
|
|
208
|
-
expect(value?.label).toEqual('12:00 AM');
|
|
209
166
|
});
|
|
210
167
|
|
|
211
168
|
test('it fires onChange callback on change', async () => {
|
|
@@ -215,10 +172,20 @@ describe('FormikTimePicker', () => {
|
|
|
215
172
|
renderForm(undefined, { onChange: mockedHandleChange })
|
|
216
173
|
);
|
|
217
174
|
|
|
218
|
-
await
|
|
175
|
+
await fireEvent.change(getByLabelText(testLabelName));
|
|
219
176
|
|
|
220
177
|
expect(mockedHandleChange).toBeCalledTimes(1);
|
|
221
178
|
});
|
|
179
|
+
|
|
180
|
+
test('it uses Formik onChange when no custom callback is provided', () => {
|
|
181
|
+
render(renderForm(undefined, {}));
|
|
182
|
+
const select = screen.getByLabelText(testLabelName);
|
|
183
|
+
const option = screen.getByText('12:15 AM') as HTMLOptionElement;
|
|
184
|
+
|
|
185
|
+
fireEvent.change(select, { target: { value: option.value } });
|
|
186
|
+
|
|
187
|
+
expect(select).toHaveValue(option.value);
|
|
188
|
+
});
|
|
222
189
|
});
|
|
223
190
|
});
|
|
224
191
|
});
|
|
@@ -21,7 +21,6 @@ export interface FormikTimePickerProps
|
|
|
21
21
|
export const FormikTimePicker: FC<FormikTimePickerProps> = ({
|
|
22
22
|
field: { name, onBlur, onChange: formikOnChange, value },
|
|
23
23
|
form: { touched, errors },
|
|
24
|
-
options,
|
|
25
24
|
onChange,
|
|
26
25
|
...props
|
|
27
26
|
}) => (
|
|
@@ -32,6 +31,5 @@ export const FormikTimePicker: FC<FormikTimePickerProps> = ({
|
|
|
32
31
|
onChange={onChange ?? formikOnChange}
|
|
33
32
|
value={value}
|
|
34
33
|
error={getIn(touched, name) && getIn(errors, name)}
|
|
35
|
-
options={options}
|
|
36
34
|
/>
|
|
37
35
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@
|
|
1
|
+
@use '@hyphen/hyphen-design-tokens/build/scss/variables' as *;
|
|
2
2
|
// The following styles required the :global tag since they need to be applied to react-select elements for which we do not own the markup
|
|
3
3
|
|
|
4
4
|
@mixin react-select-icon {
|
|
@@ -903,19 +903,19 @@ export const ComponentAsColumnHeader = () =>
|
|
|
903
903
|
const columnConfig: ColumnType[] = [
|
|
904
904
|
{ heading: 'ID', dataKey: 'id' },
|
|
905
905
|
{ heading: 'Color', dataKey: 'color' },
|
|
906
|
-
{ heading: <Badge
|
|
906
|
+
{ heading: <Badge>Status</Badge>, dataKey: 'status' },
|
|
907
907
|
];
|
|
908
908
|
const tableData = [
|
|
909
909
|
{
|
|
910
910
|
id: 1,
|
|
911
911
|
color: 'red',
|
|
912
|
-
status: <Badge
|
|
912
|
+
status: <Badge color="danger">danger</Badge>,
|
|
913
913
|
},
|
|
914
|
-
{ id: 2, color: 'blue', status: <Badge
|
|
914
|
+
{ id: 2, color: 'blue', status: <Badge color="info">info</Badge> },
|
|
915
915
|
{
|
|
916
916
|
id: 3,
|
|
917
917
|
color: 'green',
|
|
918
|
-
status: <Badge
|
|
918
|
+
status: <Badge color="success">success</Badge>,
|
|
919
919
|
},
|
|
920
920
|
];
|
|
921
921
|
return <Table rowKey="id" columns={columnConfig} rows={tableData} />;
|
|
@@ -6,13 +6,12 @@ import * as Stories from './TimePicker.stories';
|
|
|
6
6
|
|
|
7
7
|
# TimePicker
|
|
8
8
|
|
|
9
|
-
Use a TimePicker when you want users to select from a list of
|
|
9
|
+
Use a TimePicker when you want users to select from a list of available times, agnostic of date.
|
|
10
10
|
|
|
11
|
-
_NOTE:_ This component is abstracted from the [
|
|
11
|
+
_NOTE:_ This component is abstracted from the [SelectInputNative](?path=/docs/components-selectinputnative-overview--default-story)
|
|
12
12
|
and as such includes the same underlying props interface with an added method for generating the time options automatically.
|
|
13
13
|
|
|
14
|
-
_ABOUT TIME FORMAT:_
|
|
15
|
-
be a JS ISO date string, like this: `2016-07-13T18:46:01.933Z`.
|
|
14
|
+
_ABOUT TIME FORMAT:_ The value returned will always be a JS ISO date string, like this: `2016-07-13T18:46:01.933Z`.
|
|
16
15
|
|
|
17
16
|
## Props
|
|
18
17
|
|
|
@@ -53,13 +52,6 @@ The example below is shown in military (24-hour) time.
|
|
|
53
52
|
|
|
54
53
|
<Canvas of={Stories.WithCustomDateDisplay} />
|
|
55
54
|
|
|
56
|
-
## With Open Menu
|
|
57
|
-
|
|
58
|
-
The menu can be rendered open with the `menuIsOpen` prop. We do this here to confirm option generation
|
|
59
|
-
via our UI visual snapshot testing (Chromatic).
|
|
60
|
-
|
|
61
|
-
<Canvas of={Stories.WithOpenMenu} />
|
|
62
|
-
|
|
63
55
|
## Help Text
|
|
64
56
|
|
|
65
57
|
<Canvas of={Stories.HelpText} />
|
|
@@ -16,11 +16,11 @@ export default meta;
|
|
|
16
16
|
export const Default = () => {
|
|
17
17
|
const [value, setValue] = useState<string | null>(null);
|
|
18
18
|
return (
|
|
19
|
-
<Box
|
|
19
|
+
<Box>
|
|
20
20
|
<TimePicker
|
|
21
21
|
id="defaultTimePicker"
|
|
22
22
|
name="defaultTimePicker"
|
|
23
|
-
onChange={(event: ChangeEvent<
|
|
23
|
+
onChange={(event: ChangeEvent<HTMLSelectElement>) => {
|
|
24
24
|
setValue(event.target.value);
|
|
25
25
|
}}
|
|
26
26
|
label="Pick a Time"
|
|
@@ -30,74 +30,75 @@ export const Default = () => {
|
|
|
30
30
|
);
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
export const WithASpecificInterval = () =>
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
onChange={() => {}}
|
|
51
|
-
label="Pick a Time"
|
|
52
|
-
startTime={{ hour: 9, minute: 0 }}
|
|
53
|
-
endTime={{ hour: 15, minute: 31 }}
|
|
54
|
-
/>
|
|
55
|
-
</Box>
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
export const WithCustomDateDisplay = () => (
|
|
59
|
-
<Box height="360px">
|
|
60
|
-
<TimePicker
|
|
61
|
-
id="customDate"
|
|
62
|
-
name="customDate"
|
|
63
|
-
onChange={() => {}}
|
|
64
|
-
label="Pick a Time"
|
|
65
|
-
startTime={{ hour: 9, minute: 0 }}
|
|
66
|
-
endTime={{ hour: 15, minute: 31 }}
|
|
67
|
-
dateDisplayOptions={{ hour12: false, hour: '2-digit', minute: '2-digit' }}
|
|
68
|
-
/>
|
|
69
|
-
</Box>
|
|
70
|
-
);
|
|
33
|
+
export const WithASpecificInterval = () => {
|
|
34
|
+
const [value, setValue] = useState<string | null>(null);
|
|
35
|
+
return (
|
|
36
|
+
<Box>
|
|
37
|
+
<TimePicker
|
|
38
|
+
id="intervalTimePicker"
|
|
39
|
+
name="intervalTimePicker"
|
|
40
|
+
onChange={(event: ChangeEvent<HTMLSelectElement>) =>
|
|
41
|
+
setValue(event.target.value)
|
|
42
|
+
}
|
|
43
|
+
value={value}
|
|
44
|
+
label="Pick a Time"
|
|
45
|
+
interval={3600}
|
|
46
|
+
/>
|
|
47
|
+
</Box>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
71
50
|
|
|
72
|
-
export const
|
|
51
|
+
export const WithMinAndMaxTimes = () => {
|
|
73
52
|
const [value, setValue] = useState<string | null>(null);
|
|
74
53
|
return (
|
|
75
|
-
<Box
|
|
54
|
+
<Box>
|
|
76
55
|
<TimePicker
|
|
77
|
-
id="
|
|
78
|
-
name="
|
|
79
|
-
onChange={(event: ChangeEvent<
|
|
80
|
-
setValue(event.target.value)
|
|
81
|
-
}
|
|
56
|
+
id="startEnd"
|
|
57
|
+
name="startEnd"
|
|
58
|
+
onChange={(event: ChangeEvent<HTMLSelectElement>) =>
|
|
59
|
+
setValue(event.target.value)
|
|
60
|
+
}
|
|
61
|
+
value={value}
|
|
82
62
|
label="Pick a Time"
|
|
63
|
+
startTime={{ hour: 9, minute: 0 }}
|
|
64
|
+
endTime={{ hour: 15, minute: 31 }}
|
|
65
|
+
/>
|
|
66
|
+
</Box>
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const WithCustomDateDisplay = () => {
|
|
71
|
+
const [value, setValue] = useState<string | null>(null);
|
|
72
|
+
return (
|
|
73
|
+
<Box>
|
|
74
|
+
<TimePicker
|
|
75
|
+
id="customDate"
|
|
76
|
+
name="customDate"
|
|
77
|
+
onChange={(event: ChangeEvent<HTMLSelectElement>) =>
|
|
78
|
+
setValue(event.target.value)
|
|
79
|
+
}
|
|
83
80
|
value={value}
|
|
84
|
-
|
|
85
|
-
interval={3600}
|
|
81
|
+
label="Pick a Time"
|
|
86
82
|
startTime={{ hour: 9, minute: 0 }}
|
|
87
|
-
endTime={{ hour:
|
|
83
|
+
endTime={{ hour: 15, minute: 31 }}
|
|
84
|
+
dateDisplayOptions={{
|
|
85
|
+
hour12: false,
|
|
86
|
+
hour: '2-digit',
|
|
87
|
+
minute: '2-digit',
|
|
88
|
+
}}
|
|
88
89
|
/>
|
|
89
90
|
</Box>
|
|
90
91
|
);
|
|
91
92
|
};
|
|
92
93
|
|
|
93
94
|
export const HelpText = () => {
|
|
94
|
-
const [value, setValue] = useState<string>(
|
|
95
|
+
const [value, setValue] = useState<string | null>(null);
|
|
95
96
|
return (
|
|
96
|
-
<Box
|
|
97
|
+
<Box>
|
|
97
98
|
<TimePicker
|
|
98
99
|
id="helpText"
|
|
99
100
|
name="helpText"
|
|
100
|
-
onChange={(event: ChangeEvent<
|
|
101
|
+
onChange={(event: ChangeEvent<HTMLSelectElement>) => {
|
|
101
102
|
setValue(event.target.value);
|
|
102
103
|
}}
|
|
103
104
|
label="Pick a Time"
|
|
@@ -109,15 +110,15 @@ export const HelpText = () => {
|
|
|
109
110
|
};
|
|
110
111
|
|
|
111
112
|
export const Sizes = () => {
|
|
112
|
-
const [value, setValue] = useState<string>();
|
|
113
|
-
const [value1, setValue1] = useState<string>();
|
|
114
|
-
const [value2, setValue2] = useState<string>();
|
|
113
|
+
const [value, setValue] = useState<string | null>(null);
|
|
114
|
+
const [value1, setValue1] = useState<string | null>(null);
|
|
115
|
+
const [value2, setValue2] = useState<string | null>(null);
|
|
115
116
|
return (
|
|
116
|
-
<Box gap="md"
|
|
117
|
+
<Box gap="md">
|
|
117
118
|
<TimePicker
|
|
118
119
|
id="smTimePicker"
|
|
119
120
|
name="smTimePicker"
|
|
120
|
-
onChange={(event: ChangeEvent<
|
|
121
|
+
onChange={(event: ChangeEvent<HTMLSelectElement>) => {
|
|
121
122
|
setValue(event.target.value);
|
|
122
123
|
}}
|
|
123
124
|
label="Small"
|
|
@@ -127,7 +128,7 @@ export const Sizes = () => {
|
|
|
127
128
|
<TimePicker
|
|
128
129
|
id="mdTimePicker"
|
|
129
130
|
name="mdTimePicker"
|
|
130
|
-
onChange={(event: ChangeEvent<
|
|
131
|
+
onChange={(event: ChangeEvent<HTMLSelectElement>) => {
|
|
131
132
|
setValue1(event.target.value);
|
|
132
133
|
}}
|
|
133
134
|
label="Medium"
|
|
@@ -137,7 +138,7 @@ export const Sizes = () => {
|
|
|
137
138
|
<TimePicker
|
|
138
139
|
id="lgTimePicker"
|
|
139
140
|
name="lgTimePicker"
|
|
140
|
-
onChange={(event: ChangeEvent<
|
|
141
|
+
onChange={(event: ChangeEvent<HTMLSelectElement>) => {
|
|
141
142
|
setValue2(event.target.value);
|
|
142
143
|
}}
|
|
143
144
|
label="Large"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { screen, render } from '@testing-library/react';
|
|
2
|
+
import { screen, render, fireEvent } from '@testing-library/react';
|
|
3
3
|
import { TimePicker } from './TimePicker';
|
|
4
4
|
|
|
5
5
|
describe('TimePicker', () => {
|
|
@@ -12,8 +12,6 @@ describe('TimePicker', () => {
|
|
|
12
12
|
onChange={() => null}
|
|
13
13
|
value={null}
|
|
14
14
|
label="Select Time"
|
|
15
|
-
menuIsOpen
|
|
16
|
-
maxMenuHeight={2000}
|
|
17
15
|
/>
|
|
18
16
|
);
|
|
19
17
|
|
|
@@ -43,8 +41,6 @@ describe('TimePicker', () => {
|
|
|
43
41
|
onChange={() => null}
|
|
44
42
|
value={null}
|
|
45
43
|
label="Select Time"
|
|
46
|
-
menuIsOpen
|
|
47
|
-
maxMenuHeight={2000}
|
|
48
44
|
interval={3600}
|
|
49
45
|
startTime={{ hour: 9, minute: 0 }}
|
|
50
46
|
endTime={{ hour: 12, minute: 0 }}
|
|
@@ -65,6 +61,55 @@ describe('TimePicker', () => {
|
|
|
65
61
|
expect(screen.queryByText(time)).toBe(null);
|
|
66
62
|
});
|
|
67
63
|
});
|
|
64
|
+
|
|
65
|
+
it('supports intervals shorter than one minute', () => {
|
|
66
|
+
render(
|
|
67
|
+
<TimePicker
|
|
68
|
+
name="timePicker"
|
|
69
|
+
id="timePicker"
|
|
70
|
+
onChange={() => null}
|
|
71
|
+
value={null}
|
|
72
|
+
label="Select Time"
|
|
73
|
+
interval={45}
|
|
74
|
+
startTime={{ hour: 1, minute: 0 }}
|
|
75
|
+
endTime={{ hour: 1, minute: 2 }}
|
|
76
|
+
dateDisplayOptions={{
|
|
77
|
+
hour: '2-digit',
|
|
78
|
+
minute: '2-digit',
|
|
79
|
+
second: '2-digit',
|
|
80
|
+
hour12: false,
|
|
81
|
+
}}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
expect(screen.getByText('01:00:00')).toBeInTheDocument();
|
|
86
|
+
expect(screen.getByText('01:00:45')).toBeInTheDocument();
|
|
87
|
+
expect(screen.getByText('01:01:30')).toBeInTheDocument();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('Selected value', () => {
|
|
92
|
+
it('selects a matching time from a previous date', () => {
|
|
93
|
+
const savedValue = new Date(2020, 0, 1, 13, 0, 0, 123).toISOString();
|
|
94
|
+
const expectedValue = new Date();
|
|
95
|
+
expectedValue.setHours(13, 0, 0, 0);
|
|
96
|
+
|
|
97
|
+
render(
|
|
98
|
+
<TimePicker
|
|
99
|
+
name="timePicker"
|
|
100
|
+
id="timePicker"
|
|
101
|
+
onChange={() => null}
|
|
102
|
+
value={savedValue}
|
|
103
|
+
label="Select Time"
|
|
104
|
+
startTime={{ hour: 13, minute: 0 }}
|
|
105
|
+
endTime={{ hour: 14, minute: 0 }}
|
|
106
|
+
/>
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
expect(screen.getByLabelText('Select Time')).toHaveValue(
|
|
110
|
+
expectedValue.toISOString()
|
|
111
|
+
);
|
|
112
|
+
});
|
|
68
113
|
});
|
|
69
114
|
|
|
70
115
|
describe('Custom Date Display', () => {
|
|
@@ -76,8 +121,6 @@ describe('TimePicker', () => {
|
|
|
76
121
|
onChange={() => null}
|
|
77
122
|
value={null}
|
|
78
123
|
label="Select Time"
|
|
79
|
-
menuIsOpen
|
|
80
|
-
maxMenuHeight={2000}
|
|
81
124
|
dateDisplayOptions={{ hour12: false }}
|
|
82
125
|
startTime={{ hour: 13, minute: 0 }}
|
|
83
126
|
endTime={{ hour: 15, minute: 1 }}
|
|
@@ -94,4 +137,30 @@ describe('TimePicker', () => {
|
|
|
94
137
|
});
|
|
95
138
|
});
|
|
96
139
|
});
|
|
140
|
+
|
|
141
|
+
describe('Callback Handling', () => {
|
|
142
|
+
it('it fires an onchange callback with the correct value', async () => {
|
|
143
|
+
const mockedHandleChange = jest.fn(() => {}); // eslint-disable-line
|
|
144
|
+
|
|
145
|
+
render(
|
|
146
|
+
<TimePicker
|
|
147
|
+
name="timePicker"
|
|
148
|
+
id="timePicker"
|
|
149
|
+
onChange={mockedHandleChange}
|
|
150
|
+
value={null}
|
|
151
|
+
label="Select Time"
|
|
152
|
+
dateDisplayOptions={{ hour12: false }}
|
|
153
|
+
startTime={{ hour: 13, minute: 0 }}
|
|
154
|
+
endTime={{ hour: 15, minute: 1 }}
|
|
155
|
+
interval={3600}
|
|
156
|
+
/>
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const timePicker = screen.getByLabelText('Select Time');
|
|
160
|
+
|
|
161
|
+
fireEvent.change(timePicker, { target: { value: 'hello' } });
|
|
162
|
+
|
|
163
|
+
expect(mockedHandleChange).toBeCalledTimes(1);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
97
166
|
});
|