@indico-data/design-system 2.41.0 → 2.41.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 (39) hide show
  1. package/build/generated/iconTypes.ts +5 -0
  2. package/lib/components/forms/date/datePicker/DatePicker.d.ts +1 -2
  3. package/lib/components/forms/date/datePicker/__tests__/DatePicker.test.d.ts +1 -0
  4. package/lib/components/forms/date/datePicker/contants.d.ts +1 -1
  5. package/lib/components/forms/date/datePicker/index.d.ts +1 -0
  6. package/lib/components/forms/date/iconTriggerDatePicker/IconTriggerDatePicker.d.ts +3 -3
  7. package/lib/components/forms/date/iconTriggerDatePicker/__tests__/IconTriggerDatePicker.test.d.ts +1 -0
  8. package/lib/components/forms/date/inputDatePicker/SingleInputDatePicker.d.ts +5 -6
  9. package/lib/components/forms/date/inputDatePicker/__tests__/SingleInputDatePicker.test.d.ts +1 -0
  10. package/lib/components/forms/date/inputDatePicker/helpers.d.ts +1 -0
  11. package/lib/components/forms/date/inputDateRangePicker/InputDateRangePicker.d.ts +5 -6
  12. package/lib/components/forms/date/inputDateRangePicker/InputDateRangePicker.stories.d.ts +1 -1
  13. package/lib/components/forms/date/inputDateRangePicker/__tests__/InputDateRangePicker.test.d.ts +1 -0
  14. package/lib/components/index.d.ts +1 -0
  15. package/lib/index.d.ts +8 -7
  16. package/lib/index.esm.js +48 -47
  17. package/lib/index.esm.js.map +1 -1
  18. package/lib/index.js +48 -47
  19. package/lib/index.js.map +1 -1
  20. package/package.json +1 -1
  21. package/src/components/floatUI/{FloatUI.test.tsx → __tests__/FloatUI.test.tsx} +3 -3
  22. package/src/components/forms/date/datePicker/DatePicker.tsx +2 -2
  23. package/src/components/forms/date/datePicker/__tests__/DatePicker.test.tsx +55 -0
  24. package/src/components/forms/date/datePicker/contants.ts +1 -1
  25. package/src/components/forms/date/datePicker/index.ts +1 -0
  26. package/src/components/forms/date/iconTriggerDatePicker/IconTriggerDatePicker.mdx +1 -1
  27. package/src/components/forms/date/iconTriggerDatePicker/IconTriggerDatePicker.stories.tsx +0 -10
  28. package/src/components/forms/date/iconTriggerDatePicker/IconTriggerDatePicker.tsx +9 -12
  29. package/src/components/forms/date/iconTriggerDatePicker/__tests__/IconTriggerDatePicker.test.tsx +47 -127
  30. package/src/components/forms/date/inputDatePicker/SingleInputDatePicker.stories.tsx +17 -3
  31. package/src/components/forms/date/inputDatePicker/SingleInputDatePicker.tsx +31 -30
  32. package/src/components/forms/date/inputDatePicker/__tests__/SingleInputDatePicker.test.tsx +118 -0
  33. package/src/components/forms/date/inputDatePicker/helpers.ts +3 -0
  34. package/src/components/forms/date/inputDateRangePicker/InputDateRangePicker.mdx +9 -3
  35. package/src/components/forms/date/inputDateRangePicker/InputDateRangePicker.stories.tsx +41 -44
  36. package/src/components/forms/date/inputDateRangePicker/InputDateRangePicker.tsx +83 -49
  37. package/src/components/forms/date/inputDateRangePicker/__tests__/InputDateRangePicker.test.tsx +96 -0
  38. package/src/components/index.ts +1 -0
  39. /package/lib/components/floatUI/{FloatUI.test.d.ts → __tests__/FloatUI.test.d.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indico-data/design-system",
3
- "version": "2.41.0",
3
+ "version": "2.41.1",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "main": "lib/index.js",
@@ -1,7 +1,7 @@
1
1
  import { render, screen, fireEvent } from '@testing-library/react';
2
- import { FloatUI } from './FloatUI';
3
- import { Menu } from '../menu';
4
- import { Button } from '../button';
2
+ import { FloatUI } from '../FloatUI';
3
+ import { Menu } from '../../menu';
4
+ import { Button } from '../../button';
5
5
 
6
6
  describe('FloatUI Component', () => {
7
7
  it('does not display FloatUI content initially when rendered in uncontrolled mode', () => {
@@ -3,7 +3,7 @@ import { DateRange, DayPicker, Mode, OnSelectHandler } from 'react-day-picker';
3
3
  import { DatePickerProps } from './types';
4
4
  import { getCommonProps } from './contants';
5
5
 
6
- export const DatePicker = React.forwardRef<HTMLInputElement, DatePickerProps>((props) => {
6
+ export const DatePicker = (props: DatePickerProps) => {
7
7
  const {
8
8
  mode = 'single',
9
9
  className,
@@ -65,4 +65,4 @@ export const DatePicker = React.forwardRef<HTMLInputElement, DatePickerProps>((p
65
65
  const modeProps = modeMap[mode];
66
66
 
67
67
  return <DayPicker {...modeProps} {...commonProps} {...rest} />;
68
- });
68
+ };
@@ -0,0 +1,55 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { DatePicker } from '../DatePicker';
3
+
4
+ describe('DatePicker', () => {
5
+ describe('Single Date Picker', () => {
6
+ it('Renders the default mode for date picker (single)', () => {
7
+ render(<DatePicker data-testid="date-picker" />);
8
+ expect(screen.getByTestId('date-picker')).toHaveAttribute('data-mode', 'single');
9
+ });
10
+
11
+ it('renders the date picker with a default of 2 months if no months are provided', () => {
12
+ render(<DatePicker data-testid="date-picker" />);
13
+ expect(document.getElementsByClassName('rdp-month')).toHaveLength(1);
14
+ });
15
+
16
+ it('renders the date picker with a custom number of months', () => {
17
+ render(<DatePicker numberOfMonths={3} data-testid="date-picker" />);
18
+ expect(document.getElementsByClassName('rdp-month')).toHaveLength(3);
19
+ });
20
+ });
21
+
22
+ describe('Range Date Picker', () => {
23
+ it('Renders the range mode for date picker', () => {
24
+ render(<DatePicker mode="range" data-testid="date-picker" />);
25
+ expect(screen.getByTestId('date-picker')).toHaveAttribute('data-mode', 'range');
26
+ });
27
+
28
+ it('renders the date range picker with a default of 2 months if no months are provided', () => {
29
+ render(<DatePicker mode="range" data-testid="date-picker" />);
30
+ expect(document.getElementsByClassName('rdp-month')).toHaveLength(2);
31
+ });
32
+
33
+ it('renders the date range picker with a custom number of months', () => {
34
+ render(<DatePicker mode="range" numberOfMonths={3} data-testid="date-picker" />);
35
+ expect(document.getElementsByClassName('rdp-month')).toHaveLength(3);
36
+ });
37
+ });
38
+
39
+ describe('Multiple Date Picker', () => {
40
+ it('Renders the multiple mode for date picker', () => {
41
+ render(<DatePicker mode="multiple" data-testid="date-picker" />);
42
+ expect(screen.getByTestId('date-picker')).toHaveAttribute('data-mode', 'multiple');
43
+ });
44
+
45
+ it('renders the date picker with a default of 2 months if no months are provided', () => {
46
+ render(<DatePicker mode="multiple" data-testid="date-picker" />);
47
+ expect(document.getElementsByClassName('rdp-month')).toHaveLength(1);
48
+ });
49
+
50
+ it('renders the date picker with a custom number of months', () => {
51
+ render(<DatePicker mode="multiple" numberOfMonths={3} data-testid="date-picker" />);
52
+ expect(document.getElementsByClassName('rdp-month')).toHaveLength(3);
53
+ });
54
+ });
55
+ });
@@ -4,7 +4,7 @@ export const getCommonProps = (props: CommonProps) => ({
4
4
  className: props.className,
5
5
  id: props.id,
6
6
  month: props.month,
7
- captionLayout: props.captionLayout,
7
+ captionLayout: props.captionLayout ?? 'dropdown',
8
8
  defaultMonth: props.defaultMonth,
9
9
  startMonth: props.startMonth,
10
10
  endMonth: props.endMonth,
@@ -0,0 +1 @@
1
+ export { DatePicker } from './DatePicker';
@@ -5,7 +5,7 @@ import { Row, Col } from '../../../grid/index';
5
5
  <Meta title="Forms/DatePicker/IconTriggerDatePicker" name="IconTriggerDatePicker" />
6
6
 
7
7
  # IconTriggerDatePicker
8
- The No Input Date Picker is to be used when we need to open the datepicker with a simple icon and dont care about the user typing in a value. It leverages our DatePicker component inside of a popper window.
8
+ The Icon Trigger Date Picker is to be used when we need to open the datepicker with a simple icon and dont care about the user typing in a value. It leverages our DatePicker component inside of a popper window.
9
9
  <Canvas of={IconTriggerDatePicker.Default} />
10
10
 
11
11
  ## Props
@@ -54,16 +54,6 @@ const meta: Meta<typeof IconTriggerDatePicker> = {
54
54
  },
55
55
  },
56
56
  },
57
- month: {
58
- control: 'date',
59
- description: 'The month to display.',
60
- table: {
61
- category: 'Props',
62
- type: {
63
- summary: 'Date',
64
- },
65
- },
66
- },
67
57
  triggerIcon: {
68
58
  control: 'text',
69
59
  description: 'The icon to use as a trigger.',
@@ -12,14 +12,14 @@ interface Props {
12
12
  isDisabled?: boolean;
13
13
  id: string;
14
14
  label?: string;
15
- onSelect?: (selected: Date | DateRange | Date[] | undefined) => void;
16
- month?: Date;
17
- selected?: Date | DateRange | Date[] | undefined;
15
+ onSelect?: (selected: Date | DateRange | undefined) => void;
16
+ selected?: Date | DateRange | undefined;
18
17
  triggerIcon: IconName;
19
18
  triggerIconSize: IconSizes;
20
19
  isOpen?: boolean;
21
20
  clearOnClose?: boolean;
22
21
  className?: string;
22
+ initialMonth?: Date;
23
23
  'data-testid'?: string;
24
24
  }
25
25
 
@@ -30,7 +30,6 @@ export const IconTriggerDatePicker = (props: Props) => {
30
30
  isDisabled,
31
31
  disableBeforeDate,
32
32
  disableAfterDate,
33
- month,
34
33
  id,
35
34
  label,
36
35
  onSelect,
@@ -40,27 +39,24 @@ export const IconTriggerDatePicker = (props: Props) => {
40
39
  mode,
41
40
  isOpen,
42
41
  clearOnClose,
42
+ initialMonth,
43
43
  ...rest
44
44
  } = props;
45
45
 
46
- const [localSelected, setLocalSelected] = useState<Date | DateRange | Date[] | undefined>(
47
- selected || undefined,
48
- );
46
+ const [localMonth, setLocalMonth] = useState<Date>(initialMonth ?? new Date());
49
47
 
50
48
  const handleSelect: OnSelectHandler<Date> = (date) => {
51
49
  if (!date) {
52
50
  onSelect && onSelect(undefined);
53
- setLocalSelected(undefined);
54
51
  } else {
55
52
  onSelect && onSelect(date);
56
- setLocalSelected(date);
57
53
  }
58
54
  };
59
55
 
60
56
  // clear selection if clear on close is true
61
57
  useEffect(() => {
62
58
  if (!isOpen && clearOnClose) {
63
- setLocalSelected(undefined);
59
+ onSelect && onSelect(undefined);
64
60
  }
65
61
  }, [isOpen, clearOnClose]);
66
62
 
@@ -77,11 +73,12 @@ export const IconTriggerDatePicker = (props: Props) => {
77
73
  <DatePicker
78
74
  isDisabled={isDisabled}
79
75
  mode={mode}
80
- month={month}
81
- selected={localSelected as Date | DateRange | undefined}
76
+ selected={selected}
82
77
  onSelect={handleSelect}
78
+ month={localMonth}
83
79
  startMonth={disableBeforeDate}
84
80
  endMonth={disableAfterDate}
81
+ onMonthChange={setLocalMonth}
85
82
  {...rest}
86
83
  />
87
84
  </FloatUI>
@@ -1,127 +1,47 @@
1
- it.todo('reenable these');
2
- // import React from 'react';
3
- // import { render, screen } from '@testing-library/react';
4
- // import { NoInputDatePicker } from '../NoInputDatePicker';
5
- // import { DateRange } from 'react-day-picker';
6
- // import userEvent from '@testing-library/user-event';
7
-
8
- // const today = new Date();
9
- // const mockOnChange = jest.fn();
10
- // let trigger: any;
11
-
12
- // describe('NoInputDatePicker', () => {
13
- // describe('single', () => {
14
- // beforeEach(() => {
15
- // render(
16
- // <NoInputDatePicker
17
- // id={'date-picker'}
18
- // label={'Pick a date'}
19
- // value={today}
20
- // isRangePicker={false}
21
- // triggerIcon="calendar"
22
- // triggerIconSize={[20]}
23
- // onChange={(date: Date | DateRange | undefined) => {
24
- // mockOnChange(date);
25
- // }}
26
- // />,
27
- // );
28
-
29
- // trigger = screen.getByTestId('datepicker-trigger-for-date-picker');
30
- // });
31
-
32
- // it('shows single date picker', async () => {
33
- // await userEvent.click(trigger);
34
- // expect(screen.getByTestId('datepicker-dialog')).toBeVisible();
35
- // expect(screen.getByTestId('single-datepicker')).toBeVisible();
36
- // });
37
-
38
- // it('opens the date picker when clicking on the trigger', async () => {
39
- // await userEvent.click(trigger);
40
- // const datePickerDialogContainer = screen.getByTestId('datepicker-dialog');
41
- // expect(datePickerDialogContainer).toBeVisible();
42
- // });
43
-
44
- // it('emits the right date picked for single', async () => {
45
- // await userEvent.click(trigger);
46
- // const datePickerDialogContainer = screen.getByTestId('datepicker-dialog');
47
- // expect(datePickerDialogContainer).toBeVisible();
48
-
49
- // const day28 = screen.getByText('28');
50
- // await userEvent.click(day28);
51
- // expect(mockOnChange).toHaveBeenCalledWith(
52
- // new Date(today.getFullYear(), today.getMonth(), 28),
53
- // );
54
- // });
55
-
56
- // it('closes date picker on single selection', async () => {
57
- // await userEvent.click(trigger);
58
- // const datePickerDialogContainer = screen.getByTestId('datepicker-dialog');
59
- // expect(datePickerDialogContainer).toBeVisible();
60
-
61
- // const day28 = screen.getByText('28');
62
- // await userEvent.click(day28);
63
- // expect(mockOnChange).toHaveBeenCalledWith(
64
- // new Date(today.getFullYear(), today.getMonth(), 28),
65
- // );
66
- // expect(datePickerDialogContainer).not.toBeVisible();
67
- // });
68
- // });
69
-
70
- // describe('range', () => {
71
- // beforeEach(() => {
72
- // render(
73
- // <NoInputDatePicker
74
- // id={'date-picker'}
75
- // label={'Pick a date'}
76
- // value={today}
77
- // isRangePicker={true}
78
- // triggerIcon="calendar"
79
- // triggerIconSize={[20]}
80
- // onChange={(date: Date | DateRange | undefined) => {
81
- // mockOnChange(date);
82
- // }}
83
- // />,
84
- // );
85
-
86
- // trigger = screen.getByTestId('datepicker-trigger-for-date-picker');
87
- // });
88
-
89
- // it('shows ranged date picker', async () => {
90
- // await userEvent.click(trigger);
91
- // expect(screen.getByTestId('datepicker-dialog')).toBeVisible();
92
- // expect(screen.getByTestId('range-datepicker')).toBeVisible();
93
- // });
94
-
95
- // it('emits the right date picked for range', async () => {
96
- // await userEvent.click(trigger);
97
- // const datePickerDialogContainer = screen.getByTestId('datepicker-dialog');
98
- // expect(datePickerDialogContainer).toBeVisible();
99
-
100
- // const day27 = screen.getByText('27');
101
- // await userEvent.click(day27);
102
- // const day28 = screen.getByText('28');
103
- // await userEvent.click(day28);
104
-
105
- // expect(mockOnChange).toHaveBeenCalledWith({
106
- // from: new Date(today.getFullYear(), today.getMonth(), 27),
107
- // to: new Date(today.getFullYear(), today.getMonth(), 28),
108
- // });
109
- // });
110
- // it('closes date picker on both ranged selection', async () => {
111
- // await userEvent.click(trigger);
112
- // const datePickerDialogContainer = screen.getByTestId('datepicker-dialog');
113
- // expect(datePickerDialogContainer).toBeVisible();
114
-
115
- // const day27 = screen.getByText('27');
116
- // await userEvent.click(day27);
117
- // const day28 = screen.getByText('28');
118
- // await userEvent.click(day28);
119
-
120
- // expect(mockOnChange).toHaveBeenCalledWith({
121
- // from: new Date(today.getFullYear(), today.getMonth(), 27),
122
- // to: new Date(today.getFullYear(), today.getMonth(), 28),
123
- // });
124
- // expect(datePickerDialogContainer).not.toBeVisible();
125
- // });
126
- // });
127
- // });
1
+ import { render, screen } from '@testing-library/react';
2
+ import { IconTriggerDatePicker } from '../IconTriggerDatePicker';
3
+ import userEvent from '@testing-library/user-event';
4
+
5
+ describe('DatePicker', () => {
6
+ it('The date picker opens when the icon is clicked', async () => {
7
+ render(
8
+ <IconTriggerDatePicker
9
+ ariaLabel={''}
10
+ id={'date-picker'}
11
+ triggerIcon={'checkbox'}
12
+ triggerIconSize={'xs'}
13
+ data-testid={'date-picker-testid'}
14
+ />,
15
+ );
16
+
17
+ const icon = screen.getByTestId('datepicker-trigger-for-date-picker');
18
+ expect(icon).toBeInTheDocument();
19
+ await userEvent.click(icon);
20
+ expect(screen.getByTestId('date-picker-testid')).toBeInTheDocument();
21
+ });
22
+
23
+ it('handles onSelect with the correct value', async () => {
24
+ const onSelect = jest.fn();
25
+ render(
26
+ <IconTriggerDatePicker
27
+ ariaLabel={''}
28
+ id={'date-picker'}
29
+ triggerIcon={'checkbox'}
30
+ triggerIconSize={'xs'}
31
+ data-testid={'date-picker-testid'}
32
+ onSelect={onSelect}
33
+ />,
34
+ );
35
+
36
+ const icon = screen.getByTestId('datepicker-trigger-for-date-picker');
37
+ expect(icon).toBeInTheDocument();
38
+ await userEvent.click(icon);
39
+ expect(screen.getByTestId('date-picker-testid')).toBeInTheDocument();
40
+ expect(onSelect).toHaveBeenCalledTimes(0);
41
+ const day = screen.getAllByRole('button', { name: /day/i })[0];
42
+ expect(day).toBeInTheDocument();
43
+ await userEvent.click(day);
44
+ // no need to be more specific as it will cause issues with pipelines having different time zones. This was verified manually at the time of writing
45
+ expect(onSelect).toHaveBeenCalledTimes(1);
46
+ });
47
+ });
@@ -1,5 +1,5 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react';
2
- import { SingleInputDatePicker } from './SingleInputDatePicker';
2
+ import { SingleInputDatePicker, SingleInputDatePickerProps } from './SingleInputDatePicker';
3
3
  import { useArgs } from '@storybook/preview-api';
4
4
 
5
5
  const meta: Meta<typeof SingleInputDatePicker> = {
@@ -23,6 +23,18 @@ const meta: Meta<typeof SingleInputDatePicker> = {
23
23
  },
24
24
  },
25
25
  },
26
+ captionLayout: {
27
+ control: 'select',
28
+ options: ['dropdown', 'dropdown-months', 'dropdown-years', 'label'],
29
+ description:
30
+ 'The layout of the caption. Enables you to add or remove the dropdown navigation for months/years',
31
+ table: {
32
+ category: 'Props',
33
+ type: {
34
+ summary: 'dropdown | dropdown-months | dropdown-years | label',
35
+ },
36
+ },
37
+ },
26
38
  className: {
27
39
  control: false,
28
40
  description: 'Accepts a CSS class name',
@@ -163,7 +175,7 @@ const meta: Meta<typeof SingleInputDatePicker> = {
163
175
  },
164
176
  },
165
177
  },
166
- month: {
178
+ initialMonth: {
167
179
  control: 'date',
168
180
  description: 'The month to display.',
169
181
  table: {
@@ -196,9 +208,11 @@ export const SingleInput: Story = {
196
208
  clearOnClose: false,
197
209
  errorMessage: '',
198
210
  ariaLabel: 'Date Picker',
211
+ selected: new Date(),
199
212
  },
200
213
  render: (args) => {
201
- const [{ selected }, updateArgs] = useArgs();
214
+ const [{ selected }, updateArgs] = useArgs<SingleInputDatePickerProps>();
215
+
202
216
  const handleSelect = (date: Date | undefined) => {
203
217
  updateArgs({ selected: date });
204
218
  };
@@ -1,21 +1,22 @@
1
1
  import { useId, useState, useEffect } from 'react';
2
- import { format, isValid, parse } from 'date-fns';
2
+ import { isValid, parse } from 'date-fns';
3
3
  import { DatePicker } from '../datePicker/DatePicker';
4
4
  import { Input } from '../../input';
5
5
  import { IconName } from '@/types';
6
- import { DateRange } from 'react-day-picker';
7
6
  import { FloatUI } from '../../../floatUI';
7
+ import { formatDateAsString } from './helpers';
8
8
 
9
- interface SingleInputDatePickerProps {
9
+ export interface SingleInputDatePickerProps {
10
10
  ariaLabel: string;
11
11
  disableBeforeDate?: Date;
12
12
  disableAfterDate?: Date;
13
13
  isDisabled?: boolean;
14
+ captionLayout?: 'dropdown' | 'dropdown-months' | 'dropdown-years' | 'label';
14
15
  id?: string;
15
16
  label?: string;
16
- onSelect?: (selected: Date | undefined) => void;
17
- month?: Date;
18
- selected?: Date | DateRange | Date[] | undefined;
17
+ onSelect: (selected: Date | undefined) => void;
18
+ initialMonth?: Date;
19
+ selected?: Date;
19
20
  isOpen?: boolean;
20
21
  clearOnClose?: boolean;
21
22
  className?: string;
@@ -33,10 +34,10 @@ export function SingleInputDatePicker(props: SingleInputDatePickerProps) {
33
34
  isDisabled,
34
35
  disableBeforeDate,
35
36
  disableAfterDate,
36
- month,
37
+ captionLayout,
38
+ initialMonth,
37
39
  id,
38
40
  label,
39
- onSelect,
40
41
  selected,
41
42
  isOpen,
42
43
  inputPlaceholder,
@@ -44,49 +45,48 @@ export function SingleInputDatePicker(props: SingleInputDatePickerProps) {
44
45
  inputIconName,
45
46
  isClearable,
46
47
  errorMessage,
48
+ onSelect,
47
49
  ...rest
48
50
  } = props;
49
51
 
50
52
  const inputId = useId();
51
53
 
52
- // Hold the month in state to control the calendar when the input changes
53
- const [localMonth, setLocalMonth] = useState(new Date());
54
-
55
- // Hold the selected date in state
56
- const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined);
54
+ // The text value is assumed to be unneeded by the consumer.
55
+ const [localTextValue, setLocalTextValue] = useState<string>(
56
+ selected ? formatDateAsString(selected) : '',
57
+ );
57
58
 
58
- // Hold the input value in state
59
- const [inputValue, setInputValue] = useState('');
59
+ const [localMonth, setLocalMonth] = useState<Date>(initialMonth ?? selected ?? new Date());
60
60
 
61
+ // When the day picker is selected, update the text value.
61
62
  const handleDayPickerSelect = (date: Date | undefined) => {
62
63
  if (!date) {
63
- setInputValue('');
64
- setSelectedDate(undefined);
64
+ setLocalTextValue('');
65
+ onSelect(undefined);
65
66
  } else {
66
- setSelectedDate(date);
67
- setLocalMonth(date);
68
- setInputValue(format(date, 'MM/dd/yyyy'));
67
+ setLocalTextValue(formatDateAsString(date));
68
+ onSelect(date);
69
69
  }
70
70
  };
71
71
 
72
+ // When the text input is changed, update the selected date.
72
73
  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
73
- setInputValue(e.target.value); // keep the input value in sync
74
+ setLocalTextValue(e.target.value); // keep the input value in sync
74
75
 
75
76
  const parsedDate = parse(e.target.value, 'MM/dd/yyyy', new Date());
76
77
 
77
78
  if (isValid(parsedDate)) {
78
- setSelectedDate(parsedDate);
79
- setLocalMonth(parsedDate);
79
+ onSelect(parsedDate);
80
80
  } else {
81
- setSelectedDate(undefined);
81
+ onSelect(undefined);
82
82
  }
83
83
  };
84
84
 
85
85
  // clear selection if clear on close is true
86
86
  useEffect(() => {
87
87
  if (!isOpen && clearOnClose) {
88
- setSelectedDate(undefined);
89
- setInputValue('');
88
+ onSelect(undefined);
89
+ setLocalTextValue('');
90
90
  }
91
91
  }, [isOpen, clearOnClose]);
92
92
 
@@ -94,7 +94,7 @@ export function SingleInputDatePicker(props: SingleInputDatePickerProps) {
94
94
  <FloatUI isOpen={isOpen} ariaLabel={ariaLabel}>
95
95
  <Input
96
96
  id={inputId}
97
- value={inputValue}
97
+ value={localTextValue}
98
98
  placeholder={inputPlaceholder}
99
99
  isDisabled={isDisabled}
100
100
  iconName={inputIconName}
@@ -105,11 +105,12 @@ export function SingleInputDatePicker(props: SingleInputDatePickerProps) {
105
105
  name={'Date Picker'}
106
106
  />
107
107
  <DatePicker
108
- month={localMonth}
109
- onMonthChange={setLocalMonth}
108
+ captionLayout={captionLayout}
110
109
  mode="single"
111
- selected={selectedDate}
110
+ selected={selected}
112
111
  onSelect={handleDayPickerSelect}
112
+ month={localMonth}
113
+ onMonthChange={setLocalMonth}
113
114
  {...rest}
114
115
  />
115
116
  </FloatUI>