Skip to content

Commit

Permalink
fix(FilterableMultiSelect): call onMenuChange when mouse click outside (
Browse files Browse the repository at this point in the history
#17136)

* fix(FilterableMultiSelect): call onMenuChange when mouse click outside

This fixes an issue where a mouse click event outside of the menu
does not call the `onMenuChange` callback when the menu is open.

Fixes #16896

* docs(FilterableMultiSelect): add story action for `onMenuChange`

This adds an action recorder for `onMenuChange` in storybook.

---------

Co-authored-by: Taylor Jones <[email protected]>
  • Loading branch information
gi and tay1orjones committed Sep 12, 2024
1 parent fdb31d9 commit 5c70961
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -507,11 +507,12 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect<
const nextIsOpen = forceIsOpen ?? !isOpen;
setIsOpen(nextIsOpen);
validateHighlightFocus();
if (onMenuChange) {
onMenuChange(nextIsOpen);
}
}

useEffect(() => {
onMenuChange?.(isOpen);
}, [isOpen, onMenuChange]);

const {
getToggleButtonProps,
getLabelProps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,9 @@ Filterable.argTypes = {
onChange: {
action: 'onChange',
},
onMenuChange: {
action: 'onMenuChange',
},
};

export const WithLayerMultiSelect = () => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,36 @@ describe('FilterableMultiSelect', () => {
expect(screen.getAllByRole('option').length).toBe(mockProps.items.length);
});

it('should call `onMenuChange` when the user clicks on the combobox', async () => {
render(<FilterableMultiSelect {...mockProps} />);
await waitForPosition();

await userEvent.click(screen.getByRole('combobox'));
expect(mockProps.onMenuChange).toHaveBeenCalledWith(true);
});

it('should call `onMenuChange` when the user clicks on the screen', async () => {
render(<FilterableMultiSelect {...mockProps} open />);
await waitForPosition();

await userEvent.click(document.body);
expect(mockProps.onMenuChange).toHaveBeenCalledWith(false);
});

it('should initially have the menu open when open prop is provided', async () => {
render(<FilterableMultiSelect {...mockProps} open />);
await waitForPosition();

assertMenuOpen(mockProps);
});

it('should call `onMenuChange` when open prop is provided', async () => {
render(<FilterableMultiSelect {...mockProps} open />);
await waitForPosition();

expect(mockProps.onMenuChange).toHaveBeenCalledWith(true);
});

it('should open the menu with a down arrow', async () => {
render(<FilterableMultiSelect {...mockProps} />);
await waitForPosition();
Expand All @@ -64,6 +87,15 @@ describe('FilterableMultiSelect', () => {
expect(screen.getAllByRole('option').length).toBe(mockProps.items.length);
});

it('should call `onMenuChange` when the user types a down arrow', async () => {
render(<FilterableMultiSelect {...mockProps} />);
await waitForPosition();

const menuIconNode = findMenuIconNode();
await userEvent.type(menuIconNode, '{arrowdown}');
expect(mockProps.onMenuChange).toHaveBeenCalledWith(true);
});

it('should let the user toggle the menu by the menu icon', async () => {
render(<FilterableMultiSelect {...mockProps} />);
await waitForPosition();
Expand All @@ -76,6 +108,17 @@ describe('FilterableMultiSelect', () => {
assertMenuClosed();
});

it('should call `onMenuChange` when the user toggles the menu by the menu icon', async () => {
render(<FilterableMultiSelect {...mockProps} />);
await waitForPosition();

await userEvent.click(findMenuIconNode());
expect(mockProps.onMenuChange).toHaveBeenCalledWith(true);

await userEvent.click(findMenuIconNode());
expect(mockProps.onMenuChange).toHaveBeenCalledWith(false);
});

it('should not close the menu after a user makes a selection', async () => {
render(<FilterableMultiSelect {...mockProps} />);
await waitForPosition();
Expand Down

0 comments on commit 5c70961

Please sign in to comment.