diff --git a/packages/react-components/react-drawer/etc/react-drawer.api.md b/packages/react-components/react-drawer/etc/react-drawer.api.md index 37b6b074c19914..0a60e47f1d11e9 100644 --- a/packages/react-components/react-drawer/etc/react-drawer.api.md +++ b/packages/react-components/react-drawer/etc/react-drawer.api.md @@ -32,6 +32,7 @@ export type DrawerProps = ComponentProps> & { type?: 'inline' | 'overlay'; size?: 'small' | 'medium' | 'large' | 'full'; modal?: boolean; + lightDismiss?: boolean; separator?: boolean; } & Pick; diff --git a/packages/react-components/react-drawer/src/components/Drawer/Drawer.cy.tsx b/packages/react-components/react-drawer/src/components/Drawer/Drawer.cy.tsx index 78c3209b4f4e0b..da1ff5d484f34b 100644 --- a/packages/react-components/react-drawer/src/components/Drawer/Drawer.cy.tsx +++ b/packages/react-components/react-drawer/src/components/Drawer/Drawer.cy.tsx @@ -3,11 +3,21 @@ import { mount } from '@cypress/react'; import type {} from '@cypress/react'; import { FluentProvider } from '@fluentui/react-provider'; import { webLightTheme } from '@fluentui/react-theme'; -import { Drawer } from '@fluentui/react-drawer'; +import { Drawer, DrawerProps } from '@fluentui/react-drawer'; +import { dialogSurfaceClassNames } from '@fluentui/react-dialog'; const mountFluent = (element: JSX.Element) => { mount({element}); }; +const backdropSelector = `.${dialogSurfaceClassNames.backdrop}`; + +const ControlledDrawer = ({ open: initialOpen = false, ...props }: DrawerProps) => { + const [isOpen, setIsOpen] = React.useState(initialOpen); + + React.useEffect(() => setIsOpen(initialOpen), [initialOpen]); + + return setIsOpen(open)} {...props} />; +}; describe('Drawer', () => { it('render drawer component', () => { @@ -22,7 +32,7 @@ describe('Drawer', () => { return ( <> - + @@ -36,4 +46,20 @@ describe('Drawer', () => { cy.get('#button').click(); cy.get('#drawer').should('exist'); }); + + it('should dismiss the drawer when clicking the backdrop', () => { + mountFluent(); + + cy.get('#drawer').should('exist'); + cy.get(backdropSelector).click({ force: true }); + cy.get('#drawer').should('not.exist'); + }); + + it('should NOT dismiss the drawer when clicking on the backdrop if `lightDismiss` is false', () => { + mountFluent(); + + cy.get('#drawer').should('exist'); + cy.get(backdropSelector).click({ force: true }); + cy.get('#drawer').should('exist'); + }); }); diff --git a/packages/react-components/react-drawer/src/components/Drawer/Drawer.types.ts b/packages/react-components/react-drawer/src/components/Drawer/Drawer.types.ts index 810a0a399e5f43..e79b8e3a26fa6c 100644 --- a/packages/react-components/react-drawer/src/components/Drawer/Drawer.types.ts +++ b/packages/react-components/react-drawer/src/components/Drawer/Drawer.types.ts @@ -53,6 +53,13 @@ export type DrawerProps = ComponentProps> & { */ modal?: boolean; + /** + * When this is true, the drawer will be closed on a click on the overlay. + * This prop is only used when `type` is `overlay`. + * @defaultvalue true + */ + lightDismiss?: boolean; + /** * Whether the drawer has a separator line. * This prop only works when `type` is `inline`. diff --git a/packages/react-components/react-drawer/src/components/Drawer/useDrawer.ts b/packages/react-components/react-drawer/src/components/Drawer/useDrawer.ts index 6d17a79d8787fd..9d739f16143281 100644 --- a/packages/react-components/react-drawer/src/components/Drawer/useDrawer.ts +++ b/packages/react-components/react-drawer/src/components/Drawer/useDrawer.ts @@ -4,22 +4,34 @@ import { DialogProps } from '@fluentui/react-dialog'; import type { DrawerProps, DrawerState } from './Drawer.types'; +const getModalType = (modal?: DrawerProps['modal'], lightDismiss?: DrawerProps['lightDismiss']) => { + if (!modal) { + return 'non-modal'; + } + + if (!lightDismiss) { + return 'alert'; + } + + return 'modal'; +}; + /** * @internal * Create the state required to render DrawerDialog. * @param props - props from this instance of Drawer */ const useDrawerDialogProps = (props: DrawerProps) => { - const { open, onOpenChange, modal, children, ...otherProps } = props; + const { open, onOpenChange, modal, children, lightDismiss, ...otherProps } = props; const dialogProps = React.useMemo(() => { return { + modalType: getModalType(modal, lightDismiss), open, onOpenChange, - modalType: modal ? 'modal' : 'non-modal', children, } as DialogProps; - }, [children, modal, onOpenChange, open]); + }, [children, lightDismiss, modal, onOpenChange, open]); const dialogSurfaceProps = React.useMemo(() => { return { @@ -49,6 +61,7 @@ export const useDrawer_unstable = (props: DrawerProps, ref: React.Ref { + const [open, setOpen] = React.useState(false); + + return ( +
+ + +

This drawer cannot be closed when clicking outside nor using the "ESC" key

+
+ + +
+ ); +}; diff --git a/packages/react-components/react-drawer/stories/Drawer/index.stories.tsx b/packages/react-components/react-drawer/stories/Drawer/index.stories.tsx index 571b02052031f7..48f0c9d4d65b84 100644 --- a/packages/react-components/react-drawer/stories/Drawer/index.stories.tsx +++ b/packages/react-components/react-drawer/stories/Drawer/index.stories.tsx @@ -4,12 +4,13 @@ import bestPracticesMd from './DrawerBestPractices.md'; import previewMd from './DrawerPreview.md'; export { Default } from './DrawerDefault.stories'; +export { DefaultOpen } from './DrawerDefaultOpen.stories'; +export { AlwaysOpen } from './DrawerAlwaysOpen.stories'; +export { PreventClose } from './DrawerPreventClose.stories'; export { Position } from './DrawerPosition.stories'; export { Inline } from './DrawerInline.stories'; export { Size } from './DrawerSize.stories'; export { CustomSize } from './DrawerCustomSize.stories'; -export { DefaultOpen } from './DrawerDefaultOpen.stories'; -export { AlwaysOpen } from './DrawerAlwaysOpen.stories'; export { Separator } from './DrawerSeparator.stories'; export default {