From 88e9203cffd5195736e3535a5ccb63880be1697d Mon Sep 17 00:00:00 2001 From: Vehbi Karaagac Date: Thu, 12 Nov 2026 14:19:49 -0500 Subject: [PATCH] fix(TimePicker): close time options when disabled --- .../src/components/TimePicker/TimePicker.tsx | 17 +++++++--- .../TimePicker/__tests__/TimePicker.test.tsx | 34 ++++++++++++++++++- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/packages/react-core/src/components/TimePicker/TimePicker.tsx b/packages/react-core/src/components/TimePicker/TimePicker.tsx index 5bca2a797bb..d1ddd6a1e68 100644 --- a/packages/react-core/src/components/TimePicker/TimePicker.tsx +++ b/packages/react-core/src/components/TimePicker/TimePicker.tsx @@ -127,7 +127,7 @@ class TimePicker extends Component { constructor(props: TimePickerProps) { super(props); - const { is24Hour, delimiter, time, includeSeconds, isOpen } = this.props; + const { is24Hour, delimiter, time, includeSeconds, isOpen, isDisabled } = this.props; let { minTime, maxTime } = this.props; if (minTime === '') { const minSeconds = includeSeconds ? `${delimiter}00` : ''; @@ -140,7 +140,7 @@ class TimePicker extends Component { const timeRegex = this.getRegExp(); this.state = { isInvalid: false, - isTimeOptionsOpen: isOpen, + isTimeOptionsOpen: isOpen && !isDisabled, timeState: parseTime(time, timeRegex, delimiter, !is24Hour, includeSeconds), focusedIndex: null, scrollIndex: 0, @@ -211,8 +211,11 @@ class TimePicker extends Component { componentDidUpdate(prevProps: TimePickerProps, prevState: TimePickerState) { const { timeState, isTimeOptionsOpen, isInvalid, timeRegex } = this.state; - const { time, is24Hour, delimiter, includeSeconds, isOpen, minTime, maxTime } = this.props; - if (prevProps.isOpen !== isOpen) { + const { time, is24Hour, delimiter, includeSeconds, isOpen, isDisabled, minTime, maxTime } = this.props; + if (isDisabled && isTimeOptionsOpen) { + this.setState({ isTimeOptionsOpen: false, focusedIndex: null }); + this.props.setIsOpen(false); + } else if (prevProps.isOpen !== isOpen) { this.onToggle(isOpen); } @@ -374,6 +377,9 @@ class TimePicker extends Component { isValid = (time: string) => this.isValidFormat(time) && this.isValidTime(time); onToggle = (isOpen: boolean) => { + if (this.props.isDisabled) { + return; + } // on close, parse and validate input this.setState((prevState) => { const { timeRegex, isInvalid, timeState } = prevState; @@ -405,6 +411,9 @@ class TimePicker extends Component { }; onSelect = (e: any) => { + if (this.props.isDisabled) { + return; + } const { timeRegex, timeState } = this.state; const { delimiter, is24Hour, includeSeconds, setIsOpen } = this.props; const time = parseTime(e.target.textContent, timeRegex, delimiter, !is24Hour, includeSeconds); diff --git a/packages/react-core/src/components/TimePicker/__tests__/TimePicker.test.tsx b/packages/react-core/src/components/TimePicker/__tests__/TimePicker.test.tsx index 725a645a84e..0d57fd45172 100644 --- a/packages/react-core/src/components/TimePicker/__tests__/TimePicker.test.tsx +++ b/packages/react-core/src/components/TimePicker/__tests__/TimePicker.test.tsx @@ -1,5 +1,5 @@ import { StrictMode } from 'react'; -import { render, screen } from '@testing-library/react'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { TimePicker, TimePickerProps } from '../TimePicker'; @@ -19,6 +19,38 @@ describe('TimePicker', () => { expect(screen.getByLabelText('time picker')).not.toHaveClass('pf-m-error'); }); + test('does not select a time when the open time picker becomes disabled', async () => { + const user = userEvent.setup(); + const onChange = jest.fn(); + const picker = (isDisabled: boolean) => ( + + ); + const { rerender } = render(picker(false)); + const input = screen.getByRole('textbox', { name: 'time picker' }); + + await user.click(input); + const option = await screen.findByText('11:00'); + + rerender(picker(true)); + fireEvent.click(option); + + expect(onChange).not.toHaveBeenCalled(); + await waitFor(() => expect(screen.queryByText('11:00')).not.toBeInTheDocument()); + + rerender(picker(false)); + expect(screen.queryByText('11:00')).not.toBeInTheDocument(); + await user.click(input); + await user.click(await screen.findByText('11:00')); + expect(onChange).toHaveBeenCalledWith(expect.any(Object), '11:00', 11, 0, null, true); + }); + describe('test timepicker onChange method with valid values', () => { const testOnChange = async ({ inputProps,