@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.
Files changed (70) hide show
  1. package/dist/css/fonts.css +5 -3
  2. package/dist/css/fonts.css.map +1 -0
  3. package/dist/css/index.css +370 -222
  4. package/dist/css/index.css.map +1 -0
  5. package/dist/css/reset.css +5 -3
  6. package/dist/css/reset.css.map +1 -0
  7. package/dist/css/utilities.css +487 -43
  8. package/dist/css/utilities.css.map +1 -0
  9. package/dist/css/variables.css +180 -33
  10. package/dist/css/variables.css.map +1 -0
  11. package/dist/hyphen-components.cjs.development.js +250 -317
  12. package/dist/hyphen-components.cjs.development.js.map +1 -1
  13. package/dist/hyphen-components.cjs.production.min.js +2 -2
  14. package/dist/hyphen-components.cjs.production.min.js.map +1 -1
  15. package/dist/hyphen-components.esm.js +204 -271
  16. package/dist/hyphen-components.esm.js.map +1 -1
  17. package/dist/index.d.ts +25 -60
  18. package/package.json +4 -4
  19. package/src/components/Alert/Alert.mdx +1 -1
  20. package/src/components/Alert/Alert.module.scss +29 -34
  21. package/src/components/Alert/Alert.stories.tsx +11 -3
  22. package/src/components/Alert/Alert.test.tsx +17 -11
  23. package/src/components/Alert/Alert.tsx +9 -16
  24. package/src/components/Badge/Badge.mdx +46 -4
  25. package/src/components/Badge/Badge.module.scss +235 -185
  26. package/src/components/Badge/Badge.stories.tsx +126 -36
  27. package/src/components/Badge/Badge.test.tsx +180 -21
  28. package/src/components/Badge/Badge.tsx +56 -21
  29. package/src/components/Button/Button.module.scss +1 -1
  30. package/src/components/CheckboxInput/components/Checkbox.module.scss +2 -2
  31. package/src/components/Drawer/Drawer.mdx +14 -16
  32. package/src/components/Drawer/Drawer.module.scss +1 -1
  33. package/src/components/DropdownMenu/DropdownMenu.tsx +6 -8
  34. package/src/components/Formik/Formik.stories.tsx +3 -5
  35. package/src/components/Formik/FormikTimePicker/FormikTimePicker.test.tsx +34 -67
  36. package/src/components/Formik/FormikTimePicker/FormikTimePicker.tsx +0 -2
  37. package/src/components/Modal/Modal.module.scss +1 -1
  38. package/src/components/RadioGroup/RadioInput/RadioInput.module.scss +2 -2
  39. package/src/components/SelectInput/SelectInput.module.scss +1 -1
  40. package/src/components/SelectInputInset/SelectInputInset.module.scss +1 -1
  41. package/src/components/SelectInputNative/SelectInputNative.module.scss +1 -1
  42. package/src/components/Switch/Switch.module.scss +1 -1
  43. package/src/components/Table/Table.stories.tsx +4 -4
  44. package/src/components/TextInput/TextInput.module.scss +1 -1
  45. package/src/components/TextInputInset/TextInputInset.module.scss +1 -1
  46. package/src/components/TextareaInput/TextareaInput.module.scss +1 -1
  47. package/src/components/TextareaInputInset/TextareaInputInset.module.scss +1 -1
  48. package/src/components/TimePicker/TimePicker.mdx +3 -11
  49. package/src/components/TimePicker/TimePicker.stories.tsx +61 -60
  50. package/src/components/TimePicker/TimePicker.test.tsx +76 -7
  51. package/src/components/TimePicker/TimePicker.tsx +37 -7
  52. package/src/components/Toggle/Toggle.module.scss +1 -1
  53. package/src/components/ToggleGroup/ToggleGroup.module.scss +1 -1
  54. package/src/components/Tooltip/Tooltip.stories.tsx +1 -1
  55. package/src/docs/Colors.mdx +13 -0
  56. package/src/index.ts +0 -2
  57. package/src/styles/display.scss +1 -1
  58. package/src/styles/flex.scss +1 -1
  59. package/src/styles/overflow.scss +2 -0
  60. package/src/styles/position.scss +2 -0
  61. package/src/styles/text-align.scss +2 -0
  62. package/src/styles/utilities.scss +10 -9
  63. package/src/styles/variables/index.scss +2 -1
  64. package/src/styles/white-space.scss +2 -0
  65. package/src/components/Formik/FormikTimePickerNative/FormikTimePickerNative.test.tsx +0 -175
  66. package/src/components/Formik/FormikTimePickerNative/FormikTimePickerNative.tsx +0 -38
  67. package/src/components/TimePickerNative/TimePickerNative.mdx +0 -67
  68. package/src/components/TimePickerNative/TimePickerNative.stories.tsx +0 -150
  69. package/src/components/TimePickerNative/TimePickerNative.test.tsx +0 -117
  70. 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, [any]>; // eslint-disable-line
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
- render(
97
- renderForm(
98
- { label: '12:00 AM', value: '2020-10-23T04:30:00.120Z' },
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
- expect(screen.getByText('12:00 AM')).toBeInTheDocument();
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)).toBeInTheDocument();
112
- expect(screen.getByText('HH:MM')).toBeInTheDocument();
99
+ expect(screen.getByLabelText(testLabelName)).toHaveValue(
100
+ expectedValue.toISOString()
101
+ );
113
102
  });
114
103
  });
115
104
 
116
- describe('Multi select, with multiple items selected', () => {
117
- test('it renders input with a label, and with two items selected', () => {
118
- render(
119
- renderForm(
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
- const { container } = render(
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(disabledInput).toBeInTheDocument();
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(renderForm([], { isRequired: true }));
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: Option | undefined;
155
+ let value: string | undefined;
182
156
  const mockedHandleChange = jest.fn((event) => {
183
- value = event.target.value;
157
+ event.persist();
184
158
  });
185
159
 
186
- const { getByLabelText, container, getByText } = render(
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 selectEvent.select(getByLabelText(testLabelName), '12:00 AM');
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
- @import '@hyphen/hyphen-design-tokens/build/scss/variables';
1
+ @use '@hyphen/hyphen-design-tokens/build/scss/variables' as *;
2
2
 
3
3
  .modal-close {
4
4
  border: none;
@@ -1,5 +1,5 @@
1
- @import '../../../styles/mixins';
2
- @import '@hyphen/hyphen-design-tokens/build/scss/variables';
1
+ @use '../../../styles/mixins' as *;
2
+ @use '@hyphen/hyphen-design-tokens/build/scss/variables' as *;
3
3
 
4
4
  $sm-dimension: 16px;
5
5
  $md-dimension: 20px;
@@ -1,4 +1,4 @@
1
- @import '@hyphen/hyphen-design-tokens/build/scss/variables';
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 {
@@ -1,4 +1,4 @@
1
- @import '@hyphen/hyphen-design-tokens/build/scss/variables';
1
+ @use '@hyphen/hyphen-design-tokens/build/scss/variables' as *;
2
2
 
3
3
  @mixin floating-label-minimize-md {
4
4
  opacity: 0.75;
@@ -1,4 +1,4 @@
1
- @import '@hyphen/hyphen-design-tokens/build/scss/variables';
1
+ @use '@hyphen/hyphen-design-tokens/build/scss/variables' as *;
2
2
 
3
3
  %disabled-base {
4
4
  background-color: var(--color-background-disabled);
@@ -1,4 +1,4 @@
1
- @import '@hyphen/hyphen-design-tokens/build/scss/variables';
1
+ @use '@hyphen/hyphen-design-tokens/build/scss/variables' as *;
2
2
 
3
3
  @mixin thumb-size-sm {
4
4
  width: calc(var(--size-spacing-2xl) - 4px);
@@ -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 message="Status" />, dataKey: 'status' },
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 variant="red">danger</Badge>,
912
+ status: <Badge color="danger">danger</Badge>,
913
913
  },
914
- { id: 2, color: 'blue', status: <Badge variant="blue">info</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 variant="green">success</Badge>,
918
+ status: <Badge color="success">success</Badge>,
919
919
  },
920
920
  ];
921
921
  return <Table rowKey="id" columns={columnConfig} rows={tableData} />;
@@ -1,4 +1,4 @@
1
- @import '@hyphen/hyphen-design-tokens/build/scss/variables';
1
+ @use '@hyphen/hyphen-design-tokens/build/scss/variables' as *;
2
2
 
3
3
  @mixin size-sm {
4
4
  border-radius: var(
@@ -1,4 +1,4 @@
1
- @import '@hyphen/hyphen-design-tokens/build/scss/variables';
1
+ @use '@hyphen/hyphen-design-tokens/build/scss/variables' as *;
2
2
 
3
3
  @mixin floating-label-minimize-md {
4
4
  opacity: 0.75;
@@ -1,4 +1,4 @@
1
- @import '@hyphen/hyphen-design-tokens/build/scss/variables';
1
+ @use '@hyphen/hyphen-design-tokens/build/scss/variables' as *;
2
2
 
3
3
  @mixin size-sm {
4
4
  border-radius: var(
@@ -1,4 +1,4 @@
1
- @import '@hyphen/hyphen-design-tokens/build/scss/variables';
1
+ @use '@hyphen/hyphen-design-tokens/build/scss/variables' as *;
2
2
 
3
3
  @mixin floating-label-minimize-md {
4
4
  opacity: 0.75;
@@ -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 a available times agnostic of date.
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 [SelectInput](?path=/docs/components-selectinput-overview--default-story)
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:_ While the `value` prop technically returns `{ label: string; value: string; }` the value returned will always
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 height="360px">
19
+ <Box>
20
20
  <TimePicker
21
21
  id="defaultTimePicker"
22
22
  name="defaultTimePicker"
23
- onChange={(event: ChangeEvent<HTMLInputElement>) => {
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
- <Box height="360px">
35
- <TimePicker
36
- id="intervalTimePicker"
37
- name="intervalTimePicker"
38
- onChange={() => {}}
39
- label="Pick a Time"
40
- interval={3600}
41
- />
42
- </Box>
43
- );
44
-
45
- export const WithMinAndMaxTimes = () => (
46
- <Box height="360px">
47
- <TimePicker
48
- id="startEnd"
49
- name="startEnd"
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 WithOpenMenu = () => {
51
+ export const WithMinAndMaxTimes = () => {
73
52
  const [value, setValue] = useState<string | null>(null);
74
53
  return (
75
- <Box height="260px">
54
+ <Box>
76
55
  <TimePicker
77
- id="openMenu"
78
- name="openMenu"
79
- onChange={(event: ChangeEvent<HTMLInputElement>) => {
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
- menuIsOpen
85
- interval={3600}
81
+ label="Pick a Time"
86
82
  startTime={{ hour: 9, minute: 0 }}
87
- endTime={{ hour: 13, minute: 1 }}
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 height="360px">
97
+ <Box>
97
98
  <TimePicker
98
99
  id="helpText"
99
100
  name="helpText"
100
- onChange={(event: ChangeEvent<HTMLInputElement>) => {
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" height="360px">
117
+ <Box gap="md">
117
118
  <TimePicker
118
119
  id="smTimePicker"
119
120
  name="smTimePicker"
120
- onChange={(event: ChangeEvent<HTMLInputElement>) => {
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<HTMLInputElement>) => {
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<HTMLInputElement>) => {
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
  });