From a8158d32cc7980febbf82aa324ac3cde05996ff4 Mon Sep 17 00:00:00 2001 From: Amber Date: Wed, 26 Jan 2022 16:44:25 +0100 Subject: [PATCH] feat(Popup): new prop `closeOnScroll` close popup when scroll outside of it (#21453) * close on scroll * chglog * e2e --- packages/fluentui/CHANGELOG.md | 3 ++ .../e2e/tests/popupDismissScroll-example.tsx | 52 +++++++++++++++++++ .../e2e/tests/popupDismissScroll.spec.ts | 28 ++++++++++ .../src/components/Popup/Popup.tsx | 7 ++- 4 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 packages/fluentui/e2e/tests/popupDismissScroll-example.tsx create mode 100644 packages/fluentui/e2e/tests/popupDismissScroll.spec.ts diff --git a/packages/fluentui/CHANGELOG.md b/packages/fluentui/CHANGELOG.md index 3f62702fafbbb8..dbefed2dc9ec9e 100644 --- a/packages/fluentui/CHANGELOG.md +++ b/packages/fluentui/CHANGELOG.md @@ -24,6 +24,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - `FocusTrapZone`: add handleRef method instead of function to prevent calling it on each re-render @annabratseiko ([#21337](https://github.com/microsoft/fluentui/pull/21337)) - Fix color slot titles in docsite @notandrew ([#21378](https://github.com/microsoft/fluentui/pull/21378)) +### Features +- Add new Popup prop `closeOnScroll` to close popup when scroll happens outside of the popover element @yuanboxue-amber ([#21453](https://github.com/microsoft/fluentui/pull/21453)) + ## [v0.60.1](https://github.com/microsoft/fluentui/tree/@fluentui/react-northstar_v0.60.1) (2022-01-17) [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-northstar_v0.60.0..@fluentui/react-northstar_v0.60.1) diff --git a/packages/fluentui/e2e/tests/popupDismissScroll-example.tsx b/packages/fluentui/e2e/tests/popupDismissScroll-example.tsx new file mode 100644 index 00000000000000..c1fa9ef811bc27 --- /dev/null +++ b/packages/fluentui/e2e/tests/popupDismissScroll-example.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { Button, Popup, Flex } from '@fluentui/react-northstar'; + +export const selectors = { + simplePopup: { + triggerId: 'trigger', + contentId: 'content', + }, + contextPopup: { + triggerId: 'trigger-context', + contentId: 'content-context', + }, + dismissScrollPopup: { + triggerId: 'trigger-dismiss', + contentId: 'content-dismiss', + }, +}; + +const PopupClickHandlingExample = () => { + return ( + + simple popup + } + content={{ + content: 'Open a popup', + id: selectors.simplePopup.contentId, + }} + /> + popup open on context + } + content={{ + content: 'Open a popup', + id: selectors.contextPopup.contentId, + }} + on="context" + /> + popup with closeOnScroll + } + content={{ + content: 'Open a popup', + id: selectors.dismissScrollPopup.contentId, + }} + closeOnScroll + /> + + ); +}; + +export default PopupClickHandlingExample; diff --git a/packages/fluentui/e2e/tests/popupDismissScroll.spec.ts b/packages/fluentui/e2e/tests/popupDismissScroll.spec.ts new file mode 100644 index 00000000000000..a0ec61a47b634b --- /dev/null +++ b/packages/fluentui/e2e/tests/popupDismissScroll.spec.ts @@ -0,0 +1,28 @@ +import { selectors } from './popupDismissScroll-example'; + +describe('Popup - dismiss on scroll container', () => { + beforeEach(() => { + cy.gotoTestCase(__filename, `#${selectors.simplePopup.triggerId}`); + }); + + it('simple popup does not dismiss content on scroll', () => { + cy.clickOn(`#${selectors.simplePopup.triggerId}`); // opens popup + cy.visible(`#${selectors.simplePopup.contentId}`); // popup visible + cy.get('body').trigger('wheel'); // page scroll + cy.visible(`#${selectors.simplePopup.contentId}`); // popup still visible + }); + + it('popup on context dismiss content on scroll', () => { + cy.get(`#${selectors.contextPopup.triggerId}`).rightclick(); // opens popup + cy.visible(`#${selectors.contextPopup.contentId}`); // popup visible + cy.get('body').trigger('wheel'); // page scroll + cy.notExist(`#${selectors.contextPopup.contentId}`); // popup dismissed + }); + + it('popup with closeOnScroll prop dismiss content on scroll', () => { + cy.clickOn(`#${selectors.dismissScrollPopup.triggerId}`); // opens popup + cy.visible(`#${selectors.dismissScrollPopup.contentId}`); // popup visible + cy.get('body').trigger('wheel'); // page scroll + cy.notExist(`#${selectors.dismissScrollPopup.contentId}`); // popup dismissed + }); +}); diff --git a/packages/fluentui/react-northstar/src/components/Popup/Popup.tsx b/packages/fluentui/react-northstar/src/components/Popup/Popup.tsx index e81f7db8a2051e..a389745e80b510 100644 --- a/packages/fluentui/react-northstar/src/components/Popup/Popup.tsx +++ b/packages/fluentui/react-northstar/src/components/Popup/Popup.tsx @@ -131,6 +131,9 @@ export interface PopupProps /** Controls whether or not auto focus should be applied, using boolean or AutoFocusZoneProps type value. */ autoFocus?: boolean | AutoFocusZoneProps; + + /** Close the popup when scroll happens outside of Popup */ + closeOnScroll?: boolean; } export const popupClassName = 'ui-popup'; @@ -170,6 +173,7 @@ export const Popup: React.FC & unstable_disableTether, unstable_pinned, autoSize, + closeOnScroll, } = props; const [open, setOpen] = useAutoControlled({ @@ -477,7 +481,7 @@ export const Popup: React.FC & capture /> - {isOpenedByRightClick && ( + {(isOpenedByRightClick || closeOnScroll) && ( <> @@ -685,6 +689,7 @@ Popup.propTypes = { contentRef: customPropTypes.ref, trapFocus: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]), autoFocus: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]), + closeOnScroll: PropTypes.bool, }; Popup.defaultProps = { accessibility: popupBehavior,