diff --git a/packages/react/src/internals/usePressAndHold.ts b/packages/react/src/internals/usePressAndHold.ts index 45555c7025b..c6813ad7691 100644 --- a/packages/react/src/internals/usePressAndHold.ts +++ b/packages/react/src/internals/usePressAndHold.ts @@ -169,6 +169,12 @@ export function usePressAndHold(params: UsePressAndHoldParameters): UsePressAndH [stopAutoChange], ); + React.useEffect(() => { + if (disabled) { + stopAutoChange(); + } + }, [disabled, stopAutoChange]); + const pointerHandlers: UsePressAndHoldReturnValue['pointerHandlers'] = { onTouchStart() { isTouchingButtonRef.current = true; diff --git a/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx b/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx index 6c6d0847846..263b063a9db 100644 --- a/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx +++ b/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx @@ -306,6 +306,42 @@ describe('', () => { expect(input).toHaveValue('4'); }); + it('stops an active press-and-hold interaction when disabled', async () => { + function App() { + const [disabled, setDisabled] = React.useState(false); + + return ( + + + + + + ); + } + + await render(); + + const input = screen.getByRole('textbox'); + const increment = screen.getByRole('button', { name: 'Increase' }); + + fireEvent.pointerDown(increment, { + button: 0, + pointerType: 'mouse', + }); + + expect(input).toHaveValue('1'); + + fireEvent.click(screen.getByRole('button', { name: 'Disable' })); + + clock.tick(START_AUTO_CHANGE_DELAY); + clock.tick(CHANGE_VALUE_TICK_DELAY); + clock.tick(CHANGE_VALUE_TICK_DELAY); + + expect(input).toHaveValue('1'); + }); + it('removes the global release listener when unmounted during a hold', async () => { const addEventListener = vi.spyOn(window, 'addEventListener'); const removeEventListener = vi.spyOn(window, 'removeEventListener'); diff --git a/packages/react/src/number-field/root/NumberFieldRoot.test.tsx b/packages/react/src/number-field/root/NumberFieldRoot.test.tsx index 96693587308..3cd7dec6bb5 100644 --- a/packages/react/src/number-field/root/NumberFieldRoot.test.tsx +++ b/packages/react/src/number-field/root/NumberFieldRoot.test.tsx @@ -931,6 +931,26 @@ describe('', () => { const input = screen.getByRole('textbox'); expect(input).toHaveAttribute('disabled'); }); + + it('stops an active press-and-hold interaction when disabled', async () => { + const { setProps } = await render(); + const input = screen.getByRole('textbox'); + + fireEvent.pointerDown(screen.getByLabelText('Increase'), { + button: 0, + pointerType: 'mouse', + }); + expect(input).toHaveValue('1'); + + await setProps({ disabled: true }); + await act(async () => { + await new Promise((resolve) => { + setTimeout(resolve, 500); + }); + }); + + expect(input).toHaveValue('1'); + }); }); describe('prop: readOnly', () => {