diff --git a/.changeset/slow-paws-punch.md b/.changeset/slow-paws-punch.md new file mode 100644 index 0000000000..8bffd71505 --- /dev/null +++ b/.changeset/slow-paws-punch.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/popover": minor +--- + +added `shouldCloseOnScroll` to control the popover closing on scroll (#3594) diff --git a/apps/docs/content/docs/components/popover.mdx b/apps/docs/content/docs/components/popover.mdx index 9dfa13102d..5576df40db 100644 --- a/apps/docs/content/docs/components/popover.mdx +++ b/apps/docs/content/docs/components/popover.mdx @@ -167,7 +167,8 @@ You can customize the `Popover` component by passing custom Tailwind CSS classes | showArrow | `boolean` | Whether the popover should have an arrow. | `false` | | shouldFlip | `boolean` | Whether the popover should change its placement and flip when it's about to overflow its boundary area. | `true` | | triggerScaleOnOpen | `boolean` | Whether the trigger should scale down when the popover is open. | `true` | -| shouldBlockScroll | `boolean` | Whether to block scrolling outside the popover. | `false` | +| shouldBlockScroll | `boolean` | Whether the popover should block the scroll outside the popover. | `true` | +| shouldCloseOnScroll | `boolean` | Wheather the popover should close on scroll | `false` | | isKeyboardDismissDisabled | `boolean` | Whether pressing the escape key to close the popover should be disabled. | `false` | | shouldCloseOnBlur | `boolean` | Whether the popover should close when focus is lost or moves outside it. | `false` | | motionProps | [MotionProps](#motion-props) | The props to modify the framer motion animation. Use the `variants` API to create your own animation. | | diff --git a/packages/components/popover/__tests__/popover.test.tsx b/packages/components/popover/__tests__/popover.test.tsx index a73021d666..0f443d4db3 100644 --- a/packages/components/popover/__tests__/popover.test.tsx +++ b/packages/components/popover/__tests__/popover.test.tsx @@ -348,3 +348,36 @@ describe("Popover", () => { expect(popover).toHaveAttribute("aria-expanded", "false"); }); }); + +it("should close popover on scroll when shouldCloseOnScroll is false", async () => { + const wrapper = render( + + + + + + + + , + ); + + const popover = wrapper.getByTestId("popover"); + + // open popover + await act(async () => { + await userEvent.click(popover); + }); + + // assert that the popover is open + expect(popover).toHaveAttribute("aria-expanded", "true"); + + // scroll it + fireEvent.scroll(document.body); + + // assert that the popover is still open + expect(popover).toHaveAttribute("aria-expanded", "true"); +}); diff --git a/packages/components/popover/src/use-aria-popover.ts b/packages/components/popover/src/use-aria-popover.ts index d8f1c78067..1b9cb8d485 100644 --- a/packages/components/popover/src/use-aria-popover.ts +++ b/packages/components/popover/src/use-aria-popover.ts @@ -37,6 +37,11 @@ export interface Props { * @default [] */ updatePositionDeps?: any[]; + /** + * Whether the popover should close on scroll. + * @default true + */ + shouldCloseOnScroll?: boolean; } export type ReactAriaPopoverProps = Props & Omit & AriaOverlayProps; @@ -60,6 +65,7 @@ export function useReactAriaPopover( boundaryElement, isDismissable = true, shouldCloseOnBlur = true, + shouldCloseOnScroll = true, placement: placementProp = "top", containerPadding, shouldCloseOnInteractOutside, @@ -102,7 +108,7 @@ export function useReactAriaPopover( containerPadding, placement: toReactAriaPlacement(placementProp), offset: showArrow ? offset + 3 : offset, - onClose: isNonModal ? state.close : () => {}, + onClose: isNonModal && shouldCloseOnScroll ? state.close : () => {}, }); useSafeLayoutEffect(() => { diff --git a/packages/components/popover/src/use-popover.ts b/packages/components/popover/src/use-popover.ts index 66321c6968..81641db1ed 100644 --- a/packages/components/popover/src/use-popover.ts +++ b/packages/components/popover/src/use-popover.ts @@ -118,6 +118,7 @@ export function usePopover(originalProps: UsePopoverProps) { boundaryElement, isKeyboardDismissDisabled, shouldCloseOnInteractOutside, + shouldCloseOnScroll, motionProps, className, classNames, @@ -169,6 +170,7 @@ export function usePopover(originalProps: UsePopoverProps) { containerPadding, updatePositionDeps, isKeyboardDismissDisabled, + shouldCloseOnScroll, shouldCloseOnInteractOutside, }, state, diff --git a/packages/components/popover/stories/popover.stories.tsx b/packages/components/popover/stories/popover.stories.tsx index 38e7dab459..72f7efdf04 100644 --- a/packages/components/popover/stories/popover.stories.tsx +++ b/packages/components/popover/stories/popover.stories.tsx @@ -81,6 +81,11 @@ export default { type: "boolean", }, }, + shouldCloseOnScroll: { + control: { + type: "boolean", + }, + }, disableAnimation: { control: { type: "boolean",