From 0d1d22dc5b8254ed47687d08f6cce70429d79d92 Mon Sep 17 00:00:00 2001 From: Evgeny Alaev Date: Wed, 19 Jun 2024 14:44:54 +0300 Subject: [PATCH] fix(Select): do not trigger onOpenChange in case of controlled open --- src/components/Select/Select.tsx | 17 +++++++++++++---- .../__tests__/Select.base-actions.test.tsx | 5 ++--- src/hooks/useSelect/useSelect.ts | 7 ++++--- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/components/Select/Select.tsx b/src/components/Select/Select.tsx index f66827886a..0d7dd12eb6 100644 --- a/src/components/Select/Select.tsx +++ b/src/components/Select/Select.tsx @@ -178,6 +178,15 @@ export const Select = React.forwardRef(function const isErrorIconVisible = isErrorStateVisible && Boolean(errorMessage) && errorPlacement === 'inside'; + const toggleOpenIfNeeded = React.useCallback( + (nextOpen?: boolean) => { + if (typeof propsOpen === 'undefined') { + toggleOpen(nextOpen); + } + }, + [propsOpen, toggleOpen], + ); + const handleOptionClick = React.useCallback( (option?: FlattenOption) => { if (!option || option?.disabled || 'label' in option) { @@ -215,12 +224,12 @@ export const Select = React.forwardRef(function } if ([KeyCode.ARROW_DOWN, KeyCode.ARROW_UP].includes(e.key) && !open) { e.preventDefault(); - toggleOpen(); + toggleOpenIfNeeded(); } listRef?.current?.onKeyDown(e); }, - [handleOptionClick, open, toggleOpen], + [open, handleOptionClick, toggleOpenIfNeeded], ); const handleFilterKeyDown = React.useCallback((e: React.KeyboardEvent) => { @@ -262,7 +271,7 @@ export const Select = React.forwardRef(function inlineStyles.width = width; } - const handleClose = React.useCallback(() => toggleOpen(false), [toggleOpen]); + const handleClose = React.useCallback(() => toggleOpenIfNeeded(false), [toggleOpenIfNeeded]); const {onFocus, onBlur} = props; const {focusWithinProps} = useFocusWithin({ onFocusWithin: onFocus, @@ -332,7 +341,7 @@ export const Select = React.forwardRef(function style={inlineStyles} > { expect(onOpenChange).toHaveBeenCalledWith(false); expect(onOpenChange).toHaveBeenCalledTimes(2); }); - test('should call onOpenChange whith controlled open', async () => { + test('should not call onOpenChange with controlled open', async () => { const onOpenChange = jest.fn(); setup({open: true, onOpenChange}); await toggleSelectPopup(); - expect(onOpenChange).toHaveBeenCalledWith(false); - expect(onOpenChange).toHaveBeenCalledTimes(1); + expect(onOpenChange).toHaveBeenCalledTimes(0); }); }); diff --git a/src/hooks/useSelect/useSelect.ts b/src/hooks/useSelect/useSelect.ts index 0b7d62658f..162893cc60 100644 --- a/src/hooks/useSelect/useSelect.ts +++ b/src/hooks/useSelect/useSelect.ts @@ -30,10 +30,11 @@ export const useSelect = ({ const nextValue = [option.value]; setValue(nextValue); } - - toggleOpen(false); + if (typeof open === 'undefined') { + toggleOpen(false); + } }, - [value, setValue, toggleOpen], + [value, open, setValue, toggleOpen], ); const handleMultipleSelection = React.useCallback(