Skip to content

Commit

Permalink
Merge pull request #671 from balsa-asanovic/auto-close-dropdown
Browse files Browse the repository at this point in the history
Auto close Dropdown when user clicks outside
  • Loading branch information
imobachgs authored Aug 2, 2023
2 parents c4422b4 + 6f1c0c2 commit fa00c19
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 11 deletions.
7 changes: 7 additions & 0 deletions web/package/cockpit-agama.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
-------------------------------------------------------------------
Wed Aug 2 18:59:16 UTC 2023 - Balsa Asanovic <[email protected]>

- Introduced functionality to close Dropdown automatically
when the user clicks outside of it.
(gh#openSUSE/agama#552).

-------------------------------------------------------------------
Wed Aug 2 10:03:23 UTC 2023 - Imobach Gonzalez Sosa <[email protected]>

Expand Down
40 changes: 30 additions & 10 deletions web/src/components/core/PageOptions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
* find current contact information at www.suse.com.
*/

import React, { useState } from 'react';
import React, { useState, useEffect, useRef } from 'react';
import { Button, Dropdown, DropdownItem, DropdownGroup } from '@patternfly/react-core';
import { Icon, PageOptions as PageOptionsSlot } from "~/components/layout";

Expand Down Expand Up @@ -114,20 +114,40 @@ const Item = ({ children, ...props }) => {
*/
const PageOptions = ({ children }) => {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef(null);

const onToggle = () => setIsOpen(!isOpen);
const onSelect = () => setIsOpen(false);

useEffect(() => {
const handleClickOutside = (event) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
setIsOpen(false);
}
};

if (isOpen) {
document.addEventListener('click', handleClickOutside);
}

return () => {
document.removeEventListener('click', handleClickOutside);
};
}, [isOpen]);

return (
<PageOptionsSlot>
<Dropdown
isOpen={isOpen}
toggle={<Toggler onClick={onToggle} />}
onSelect={onSelect}
dropdownItems={Array(children)}
position="right"
className="page-options"
isGrouped
/>
<div ref={dropdownRef}>
<Dropdown
isOpen={isOpen}
toggle={<Toggler onClick={onToggle} />}
onSelect={onSelect}
dropdownItems={Array(children)}
position="right"
className="page-options"
isGrouped
/>
</div>
</PageOptionsSlot>
);
};
Expand Down
24 changes: 23 additions & 1 deletion web/src/components/core/PageOptions.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
*/

import React from "react";
import { screen } from "@testing-library/react";
import { screen, fireEvent } from "@testing-library/react";
import { plainRender, mockLayout } from "~/test-utils";
import { PageOptions } from "~/components/core";

Expand Down Expand Up @@ -74,3 +74,25 @@ it("hide the component content when the user clicks on one of its actions", asyn

expect(screen.queryByRole("menuitem", { name: "A dummy action" })).toBeNull();
});

it('should close the dropdown on click outside', async () => {
const { user } = plainRender(
<PageOptions>
<PageOptions.Item><>Item 1</></PageOptions.Item>
<PageOptions.Item><>Item 2</></PageOptions.Item>
</PageOptions>
);

// Open the dropdown
const toggler = screen.getByRole("button");
await user.click(toggler);

// Ensure the dropdown is open
screen.getByRole("menuitem", { name: "Item 2" });

// Click outside the dropdown
fireEvent.click(document);

// Ensure the dropdown is closed
expect(screen.queryByRole("menuitem", { name: "Item 2" })).toBeNull();
});

0 comments on commit fa00c19

Please sign in to comment.