diff --git a/apps/website/screens/components/popover/code/PopoverCodePage.tsx b/apps/website/screens/components/popover/code/PopoverCodePage.tsx index 8dcd67c1e..78d1d2529 100644 --- a/apps/website/screens/components/popover/code/PopoverCodePage.tsx +++ b/apps/website/screens/components/popover/code/PopoverCodePage.tsx @@ -95,10 +95,20 @@ const sections = [ {"() => void"} + Callback function when the popover is closed. + - + + - Callback function when the popover is opened. Used only in controlled mode and if the trigger lacks the - events to manage the controlled behavior. + + + onCloseAutoFocus + + + + {"(event: Event) => void"} + Callback function when the popover is closed and the focus is set back to the trigger element. - @@ -106,7 +116,26 @@ const sections = [ {"() => void"} - Callback function when the popover is closed. + + Callback function when the popover is opened. Used only in controlled mode and if the trigger lacks the + events to manage the controlled behavior. + + - + + + + + + onOpenAutoFocus + + + + {"(event: Event) => void"} + + + Callback function when the popover is opened and the focus is set to the first focusable element inside + the popover. + - diff --git a/packages/lib/src/popover/Popover.test.tsx b/packages/lib/src/popover/Popover.test.tsx index 5eb428b48..774e550af 100644 --- a/packages/lib/src/popover/Popover.test.tsx +++ b/packages/lib/src/popover/Popover.test.tsx @@ -1,4 +1,4 @@ -import { render } from "@testing-library/react"; +import { render, waitFor } from "@testing-library/react"; import DxcPopover from "./Popover"; import userEvent from "@testing-library/user-event"; import DxcButton from "../button/Button"; @@ -77,4 +77,33 @@ describe("Popover component tests", () => { userEvent.unhover(getByText("Trigger")); expect(onClose).toHaveBeenCalled(); }); + + test("The component manages onOpenAutoFocus", () => { + const autoFocusEvent = jest.fn(); + const { getByText, queryByText } = render( + Popover content}> + Trigger + + ); + expect(queryByText("Trigger")).toBeTruthy(); + userEvent.click(getByText("Trigger")); + expect(getByText("Popover content")).toBeTruthy(); + expect(autoFocusEvent).toHaveBeenCalled(); + }); + + test("The component manages onCloseAutoFocus", async () => { + const autoFocusEvent = jest.fn(); + const { getByText, queryByText } = render( + Popover content}> + Trigger + + ); + expect(queryByText("Trigger")).toBeTruthy(); + userEvent.click(getByText("Trigger")); + expect(getByText("Popover content")).toBeTruthy(); + userEvent.keyboard("{Escape}"); + await waitFor(() => { + expect(autoFocusEvent).toHaveBeenCalled(); + }); + }); }); diff --git a/packages/lib/src/popover/Popover.tsx b/packages/lib/src/popover/Popover.tsx index 05ae64753..6ea605579 100644 --- a/packages/lib/src/popover/Popover.tsx +++ b/packages/lib/src/popover/Popover.tsx @@ -39,7 +39,9 @@ const DxcPopover = ({ isOpen, offset = 4, onOpen, + onOpenAutoFocus, onClose, + onCloseAutoFocus, popoverContent, side = "bottom", }: PopoverPropsType): JSX.Element => { @@ -88,6 +90,12 @@ const DxcPopover = ({ align={align} side={side} sideOffset={offset} + onOpenAutoFocus={(event) => { + onOpenAutoFocus?.(event); + }} + onCloseAutoFocus={(event) => { + onCloseAutoFocus?.(event); + }} onInteractOutside={() => handleTrigger(isControlled.current, setOpened, false, onClose)} onEscapeKeyDown={() => handleTrigger(isControlled.current, setOpened, false, onClose)} onMouseEnter={ diff --git a/packages/lib/src/popover/types.ts b/packages/lib/src/popover/types.ts index 71a10d2c9..999ae1ed8 100644 --- a/packages/lib/src/popover/types.ts +++ b/packages/lib/src/popover/types.ts @@ -16,8 +16,14 @@ export type PopoverPropsType = { /** Callback function when the popover is opened. * Used only in controlled mode and if the trigger lacks the events to manage the controlled behavior. */ onOpen?: () => void; + /** Callback function when the popover is opened and the focus is set to the first focusable element inside the popover. + * */ + onOpenAutoFocus?: (event: Event) => void; /** Callback function when the popover is closed. */ onClose?: () => void; + /** Callback function when the popover is closed and the focus is set back to the trigger element. + * */ + onCloseAutoFocus?: (event: Event) => void; /** Content to be displayed inside the popover. */ popoverContent: React.ReactNode; /** Side of the trigger where the popover will appear. */