From fd51d508488549b816c5d7d0d3f89b2bac2b1065 Mon Sep 17 00:00:00 2001 From: Marcos Moura Date: Fri, 6 Oct 2023 16:06:49 +0300 Subject: [PATCH] feat(react-drawer): make dialog slot to be used for composition only (#29392) --- ...-840c300d-046b-4ec7-b733-f88067df7dea.json | 7 +++ .../react-drawer/etc/react-drawer.api.md | 16 +++--- .../react-drawer/package.json | 1 + .../src/components/Drawer/useDrawer.ts | 4 +- .../DrawerOverlay/DrawerOverlay.cy.tsx | 12 ++--- .../DrawerOverlay/DrawerOverlay.types.ts | 25 ++++++++-- .../DrawerOverlaySurface.tsx | 25 ++++++++++ .../DrawerOverlaySurface.types.ts | 17 +++++++ .../DrawerOverlaySurface/index.ts | 2 + .../useDrawerOverlaySurfaceStyles.styles.ts | 43 ++++++++++++++++ .../DrawerOverlay/renderDrawerOverlay.tsx | 6 +-- .../DrawerOverlay/useDrawerOverlay.ts | 41 ++++++++------- .../useDrawerOverlayStyles.styles.ts | 42 +++++++++------- .../src/shared/useDrawerBaseStyles.styles.ts | 5 +- .../Drawer/DrawerMotionCustom.stories.tsx | 50 +++++++------------ 15 files changed, 199 insertions(+), 97 deletions(-) create mode 100644 change/@fluentui-react-drawer-840c300d-046b-4ec7-b733-f88067df7dea.json create mode 100644 packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/DrawerOverlaySurface.tsx create mode 100644 packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/DrawerOverlaySurface.types.ts create mode 100644 packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/index.ts create mode 100644 packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/useDrawerOverlaySurfaceStyles.styles.ts diff --git a/change/@fluentui-react-drawer-840c300d-046b-4ec7-b733-f88067df7dea.json b/change/@fluentui-react-drawer-840c300d-046b-4ec7-b733-f88067df7dea.json new file mode 100644 index 0000000000000..f31ef092cb0bc --- /dev/null +++ b/change/@fluentui-react-drawer-840c300d-046b-4ec7-b733-f88067df7dea.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "feat: make dialog slot internal to be used for composition only", + "packageName": "@fluentui/react-drawer", + "email": "marcosvmmoura@gmail.com", + "dependentChangeType": "patch" +} 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 a361dd76f951a..5ea873e21df79 100644 --- a/packages/react-components/react-drawer/etc/react-drawer.api.md +++ b/packages/react-components/react-drawer/etc/react-drawer.api.md @@ -8,9 +8,8 @@ import type { ComponentProps } from '@fluentui/react-utilities'; import type { ComponentState } from '@fluentui/react-utilities'; -import { DialogProps } from '@fluentui/react-dialog'; -import { DialogSurfaceProps } from '@fluentui/react-dialog'; -import { DialogSurfaceSlots } from '@fluentui/react-dialog'; +import type { DialogProps } from '@fluentui/react-dialog'; +import type { DialogSurfaceSlots } from '@fluentui/react-dialog'; import type { ForwardRefComponent } from '@fluentui/react-utilities'; import { MotionShorthand } from '@fluentui/react-motion-preview'; import { MotionState } from '@fluentui/react-motion-preview'; @@ -131,19 +130,18 @@ export type DrawerInlineState = Required & Dra export const DrawerOverlay: ForwardRefComponent; // @public (undocumented) -export const drawerOverlayClassNames: Omit, 'dialog'>; +export const drawerOverlayClassNames: SlotClassNames; // @public export type DrawerOverlayProps = ComponentProps & Pick & DrawerBaseProps; -// @public (undocumented) -export type DrawerOverlaySlots = DialogSurfaceSlots & { - root: Slot; - dialog?: Slot; +// @public +export type DrawerOverlaySlots = { + root: Slot; }; // @public -export type DrawerOverlayState = Omit, 'backdrop'> & Required, 'backdrop'> & Required; }>; diff --git a/packages/react-components/react-drawer/package.json b/packages/react-components/react-drawer/package.json index 91068f2a3974d..61195161401a6 100644 --- a/packages/react-components/react-drawer/package.json +++ b/packages/react-components/react-drawer/package.json @@ -39,6 +39,7 @@ "@fluentui/react-jsx-runtime": "^9.0.14", "@fluentui/react-motion-preview": "^0.3.0", "@fluentui/react-shared-contexts": "^9.9.2", + "@fluentui/react-tabster": "^9.13.4", "@fluentui/react-theme": "^9.1.14", "@fluentui/react-utilities": "^9.14.1", "@griffel/react": "^1.5.14", 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 3255bc909f881..459d4cf7f77eb 100644 --- a/packages/react-components/react-drawer/src/components/Drawer/useDrawer.ts +++ b/packages/react-components/react-drawer/src/components/Drawer/useDrawer.ts @@ -15,9 +15,7 @@ import { DrawerInline } from '../DrawerInline'; * @param ref - reference to root HTMLElement of Drawer */ export const useDrawer_unstable = (props: DrawerProps, ref: React.Ref): DrawerState => { - const { type = 'overlay' } = props; - - const elementType = type === 'overlay' ? DrawerOverlay : DrawerInline; + const elementType = props.type === 'inline' ? DrawerInline : DrawerOverlay; return { components: { diff --git a/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlay.cy.tsx b/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlay.cy.tsx index 5c280f10ca0fc..290e4c7cfdced 100644 --- a/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlay.cy.tsx +++ b/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlay.cy.tsx @@ -2,11 +2,11 @@ import * as React from 'react'; import { mount } from '@cypress/react'; import { FluentProvider } from '@fluentui/react-provider'; import { webLightTheme } from '@fluentui/react-theme'; -import { dialogSurfaceClassNames } from '@fluentui/react-dialog'; import { testDrawerBaseScenarios } from '../../e2e/DrawerShared'; import { DrawerOverlay } from './DrawerOverlay'; import { DrawerOverlayProps } from './DrawerOverlay.types'; +import { drawerOverlayClassNames } from './useDrawerOverlayStyles.styles'; const mountFluent = (element: JSX.Element) => { mount({element}); @@ -28,14 +28,14 @@ describe('DrawerOverlay', () => { it('should render backdrop', () => { mountFluent(); - cy.get(`.${dialogSurfaceClassNames.backdrop}`).should('exist'); + cy.get(`.${drawerOverlayClassNames.backdrop}`).should('exist'); }); it('should close when backdrop is clicked', () => { mountFluent(); cy.get('#drawer').should('exist'); - cy.get(`.${dialogSurfaceClassNames.backdrop}`).click({ force: true }); + cy.get(`.${drawerOverlayClassNames.backdrop}`).click({ force: true }); cy.get('#drawer').should('not.exist'); }); }); @@ -44,14 +44,14 @@ describe('DrawerOverlay', () => { it('should render backdrop', () => { mountFluent(); - cy.get(`.${dialogSurfaceClassNames.backdrop}`).should('exist'); + cy.get(`.${drawerOverlayClassNames.backdrop}`).should('exist'); }); it('should not close when backdrop is clicked', () => { mountFluent(); cy.get('#drawer').should('exist'); - cy.get(`.${dialogSurfaceClassNames.backdrop}`).click({ force: true }); + cy.get(`.${drawerOverlayClassNames.backdrop}`).click({ force: true }); cy.get('#drawer').should('exist'); }); }); @@ -60,7 +60,7 @@ describe('DrawerOverlay', () => { it('should not render backdrop when modalType is default', () => { mountFluent(); - cy.get(`.${dialogSurfaceClassNames.backdrop}`).should('not.exist'); + cy.get(`.${drawerOverlayClassNames.backdrop}`).should('not.exist'); }); }); }); diff --git a/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlay.types.ts b/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlay.types.ts index 3f8080b0de446..4adfc8cfdac99 100644 --- a/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlay.types.ts +++ b/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlay.types.ts @@ -1,16 +1,28 @@ -import { DialogProps, DialogSurfaceProps, DialogSurfaceSlots } from '@fluentui/react-dialog'; +import type { DialogProps } from '@fluentui/react-dialog'; import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities'; import type { MotionState } from '@fluentui/react-motion-preview'; import type { DrawerBaseProps, DrawerBaseState } from '../../shared/DrawerBase.types'; +import { DrawerOverlaySurfaceProps } from './DrawerOverlaySurface'; -export type DrawerOverlaySlots = DialogSurfaceSlots & { - root: Slot; +/** + * DrawerOverlay slots + */ +export type DrawerOverlaySlots = { + /** + * Slot for the root element. + */ + root: Slot; +}; +/** + * DrawerOverlay internal slots for when using with composition API + */ +export type DrawerOverlayInternalSlots = DrawerOverlaySlots & { /** * Slot for the dialog component that wraps the drawer. */ - dialog?: Slot; + dialog: Slot; }; /** @@ -23,9 +35,12 @@ export type DrawerOverlayProps = ComponentProps & /** * State used in rendering DrawerOverlay */ -export type DrawerOverlayState = Omit, 'backdrop'> & +export type DrawerOverlayState = Omit, 'backdrop'> & Required< DrawerBaseState & { + /** + * Motion state for the drawer backdrop. + */ backdropMotion: MotionState; } >; diff --git a/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/DrawerOverlaySurface.tsx b/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/DrawerOverlaySurface.tsx new file mode 100644 index 0000000000000..aa254c250f1db --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/DrawerOverlaySurface.tsx @@ -0,0 +1,25 @@ +import * as React from 'react'; +import type { ForwardRefComponent } from '@fluentui/react-utilities'; +import { + useDialogSurface_unstable, + useDialogSurfaceContextValues_unstable, + renderDialogSurface_unstable, +} from '@fluentui/react-dialog'; + +import { useDrawerOverlaySurfaceStyles_unstable } from './useDrawerOverlaySurfaceStyles.styles'; +import type { DrawerOverlaySurfaceProps } from './DrawerOverlaySurface.types'; + +/** + * @internal + * DrawerOverlaySurface is a proxy for DialogSurface as is only meant to be used internally for Drawer. + */ +export const DrawerOverlaySurface: ForwardRefComponent = React.forwardRef((props, ref) => { + const dialogSurfaceState = useDialogSurface_unstable(props, ref); + const dialogSurfaceContextValues = useDialogSurfaceContextValues_unstable(dialogSurfaceState); + + useDrawerOverlaySurfaceStyles_unstable(dialogSurfaceState); + + return renderDialogSurface_unstable(dialogSurfaceState, dialogSurfaceContextValues); +}); + +DrawerOverlaySurface.displayName = 'DrawerOverlaySurface'; diff --git a/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/DrawerOverlaySurface.types.ts b/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/DrawerOverlaySurface.types.ts new file mode 100644 index 0000000000000..26334a1e95bca --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/DrawerOverlaySurface.types.ts @@ -0,0 +1,17 @@ +import type { DialogSurfaceSlots, DialogSurfaceState } from '@fluentui/react-dialog'; +import type { ComponentProps, ComponentState } from '@fluentui/react-utilities'; + +/** + * DrawerOverlaySurface slots + */ +export type DrawerOverlaySurfaceSlots = DialogSurfaceSlots; + +/** + * DrawerOverlaySurface Props + */ +export type DrawerOverlaySurfaceProps = ComponentProps; + +/** + * State used in rendering DrawerOverlaySurface + */ +export type DrawerOverlaySurfaceState = ComponentState & DialogSurfaceState; diff --git a/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/index.ts b/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/index.ts new file mode 100644 index 0000000000000..f6fa0574cb404 --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/index.ts @@ -0,0 +1,2 @@ +export * from './DrawerOverlaySurface'; +export * from './DrawerOverlaySurface.types'; diff --git a/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/useDrawerOverlaySurfaceStyles.styles.ts b/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/useDrawerOverlaySurfaceStyles.styles.ts new file mode 100644 index 0000000000000..b688cb64a6549 --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerOverlay/DrawerOverlaySurface/useDrawerOverlaySurfaceStyles.styles.ts @@ -0,0 +1,43 @@ +import { makeResetStyles, makeStyles, mergeClasses, shorthands } from '@griffel/react'; +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { tokens } from '@fluentui/react-theme'; + +import type { DrawerOverlaySurfaceSlots, DrawerOverlaySurfaceState } from './DrawerOverlaySurface.types'; + +export const drawerOverlaySurfaceClassNames: SlotClassNames = { + root: 'fui-DrawerOverlaySurface', + backdrop: 'fui-DrawerOverlaySurface__backdrop', +}; + +/** + * Styles for the backdrop slot + */ +const useBackdropResetStyles = makeResetStyles({ + ...shorthands.inset('0px'), + position: 'fixed', + backgroundColor: 'rgba(0, 0, 0, 0.4)', +}); + +const useBackdropStyles = makeStyles({ + nested: { + backgroundColor: tokens.colorTransparentBackground, + }, +}); + +/** + * Apply styling to the DrawerOverlaySurface slots based on the state + */ +export const useDrawerOverlaySurfaceStyles_unstable = (state: DrawerOverlaySurfaceState): DrawerOverlaySurfaceState => { + const backdropResetStyles = useBackdropResetStyles(); + const backdropStyles = useBackdropStyles(); + + if (state.backdrop) { + state.backdrop.className = mergeClasses( + backdropResetStyles, + state.isNestedDialog && backdropStyles.nested, + state.backdrop.className, + ); + } + + return state; +}; diff --git a/packages/react-components/react-drawer/src/components/DrawerOverlay/renderDrawerOverlay.tsx b/packages/react-components/react-drawer/src/components/DrawerOverlay/renderDrawerOverlay.tsx index b799726ae5d3f..5fcf9addfa8eb 100644 --- a/packages/react-components/react-drawer/src/components/DrawerOverlay/renderDrawerOverlay.tsx +++ b/packages/react-components/react-drawer/src/components/DrawerOverlay/renderDrawerOverlay.tsx @@ -2,17 +2,17 @@ /** @jsxImportSource @fluentui/react-jsx-runtime */ import { assertSlots } from '@fluentui/react-utilities'; -import type { DrawerOverlayState, DrawerOverlaySlots } from './DrawerOverlay.types'; +import type { DrawerOverlayState, DrawerOverlayInternalSlots } from './DrawerOverlay.types'; /** * Render the final JSX of DrawerOverlay */ export const renderDrawerOverlay_unstable = (state: DrawerOverlayState) => { - if (!state.dialog || !state.motion.canRender) { + if (!state.motion.canRender) { return null; } - assertSlots(state); + assertSlots(state); return ( diff --git a/packages/react-components/react-drawer/src/components/DrawerOverlay/useDrawerOverlay.ts b/packages/react-components/react-drawer/src/components/DrawerOverlay/useDrawerOverlay.ts index a7223c94c89d0..da080996b9ba9 100644 --- a/packages/react-components/react-drawer/src/components/DrawerOverlay/useDrawerOverlay.ts +++ b/packages/react-components/react-drawer/src/components/DrawerOverlay/useDrawerOverlay.ts @@ -1,10 +1,11 @@ import * as React from 'react'; import { slot, useMergedRefs } from '@fluentui/react-utilities'; -import { Dialog, DialogSurface } from '@fluentui/react-dialog'; +import { Dialog } from '@fluentui/react-dialog'; import { useMotion } from '@fluentui/react-motion-preview'; import { useDrawerDefaultProps } from '../../shared/useDrawerDefaultProps'; import type { DrawerOverlayProps, DrawerOverlayState } from './DrawerOverlay.types'; +import { DrawerOverlaySurface } from './DrawerOverlaySurface'; /** * Create the state required to render DrawerOverlay. @@ -25,44 +26,48 @@ export const useDrawerOverlay_unstable = ( const drawerMotion = useMotion(open); const backdropMotion = useMotion(open); - const hasCustomBackdrop = modalType !== 'non-modal' && props.backdrop !== null; + const backdropInnerProps = slot.resolveShorthand(props.backdrop); + const hasCustomBackdrop = modalType !== 'non-modal' && backdropInnerProps !== null; + const backdropProps = { + ...backdropInnerProps, + ref: useMergedRefs(backdropMotion.ref, backdropInnerProps?.ref), + }; const root = slot.always( { ...props, - ref: useMergedRefs(ref, drawerMotion.ref), + backdrop: hasCustomBackdrop ? backdropProps : null, }, { - elementType: DialogSurface, + elementType: DrawerOverlaySurface, defaultProps: { - backdrop: slot.optional(props.backdrop, { - elementType: 'div', - renderByDefault: hasCustomBackdrop, - defaultProps: { - ref: backdropMotion.ref, - }, - }), + ref: useMergedRefs(ref, drawerMotion.ref), }, }, ); - const dialog = slot.optional(props.dialog, { - elementType: Dialog, - renderByDefault: true, - defaultProps: { + const dialog = slot.always( + { open: true, defaultOpen, onOpenChange, inertTrapFocus, modalType, + /* + * children is not needed here because we construct the children in the render function, + * but it's required by DialogProps + */ + children: null as unknown as JSX.Element, }, - }); + { + elementType: Dialog, + }, + ); return { components: { - root: DialogSurface, + root: DrawerOverlaySurface, dialog: Dialog, - backdrop: 'div', }, root, diff --git a/packages/react-components/react-drawer/src/components/DrawerOverlay/useDrawerOverlayStyles.styles.ts b/packages/react-components/react-drawer/src/components/DrawerOverlay/useDrawerOverlayStyles.styles.ts index 35e7430cb5958..2ac2952e30e45 100644 --- a/packages/react-components/react-drawer/src/components/DrawerOverlay/useDrawerOverlayStyles.styles.ts +++ b/packages/react-components/react-drawer/src/components/DrawerOverlay/useDrawerOverlayStyles.styles.ts @@ -1,9 +1,11 @@ import * as React from 'react'; -import { makeStyles, mergeClasses } from '@griffel/react'; +import { makeResetStyles, makeStyles, mergeClasses } from '@griffel/react'; import { tokens } from '@fluentui/react-theme'; import type { SlotClassNames } from '@fluentui/react-utilities'; +import { createFocusOutlineStyle } from '@fluentui/react-tabster'; -import type { DrawerOverlaySlots, DrawerOverlayState } from './DrawerOverlay.types'; +import type { DrawerOverlayState } from './DrawerOverlay.types'; +import { DrawerOverlaySurfaceSlots } from './DrawerOverlaySurface/DrawerOverlaySurface.types'; import { drawerCSSVars, drawerDefaultStyles, @@ -11,7 +13,7 @@ import { useDrawerDurationStyles, } from '../../shared/useDrawerBaseStyles.styles'; -export const drawerOverlayClassNames: Omit, 'dialog'> = { +export const drawerOverlayClassNames: SlotClassNames = { root: 'fui-DrawerOverlay', backdrop: 'fui-DrawerOverlay__backdrop', }; @@ -19,18 +21,19 @@ export const drawerOverlayClassNames: Omit, ' /** * Styles for the root slot */ -const useDrawerRootStyles = makeStyles({ - root: { - ...drawerDefaultStyles, - position: 'fixed', - top: 0, - bottom: 0, - opacity: 0, - boxShadow: '0px transparent', - transitionProperty: 'transform, box-shadow, opacity', - willChange: 'transform, box-shadow, opacity', - }, +const useDrawerResetStyles = makeResetStyles({ + ...createFocusOutlineStyle(), + ...drawerDefaultStyles, + position: 'fixed', + top: 0, + bottom: 0, + opacity: 0, + boxShadow: `0px ${tokens.colorTransparentBackground}`, + transitionProperty: 'transform, box-shadow, opacity', + willChange: 'transform, box-shadow, opacity', +}); +const useDrawerRootStyles = makeStyles({ /* Positioning */ start: { transform: `translate3D(calc(var(${drawerCSSVars.drawerSizeVar}) * -1), 0, 0)`, @@ -50,7 +53,7 @@ const useDrawerRootStyles = makeStyles({ /** * Styles for the backdrop slot */ -const useBackdropMotionStyles = makeStyles({ +const useBackdropStyles = makeStyles({ backdrop: { opacity: 0, transitionProperty: 'opacity', @@ -68,8 +71,9 @@ const useBackdropMotionStyles = makeStyles({ */ export const useDrawerOverlayStyles_unstable = (state: DrawerOverlayState): DrawerOverlayState => { const baseClassNames = useDrawerBaseClassNames(state); + const resetStyles = useDrawerResetStyles(); const rootStyles = useDrawerRootStyles(); - const backdropMotionStyles = useBackdropMotionStyles(); + const backdropStyles = useBackdropStyles(); const durationStyles = useDrawerDurationStyles(); const backdrop = state.root.backdrop as React.HTMLAttributes | undefined; @@ -77,7 +81,7 @@ export const useDrawerOverlayStyles_unstable = (state: DrawerOverlayState): Draw state.root.className = mergeClasses( drawerOverlayClassNames.root, baseClassNames, - rootStyles.root, + resetStyles, rootStyles[state.position], state.motion.active && rootStyles.visible, state.root.className, @@ -86,9 +90,9 @@ export const useDrawerOverlayStyles_unstable = (state: DrawerOverlayState): Draw if (backdrop) { backdrop.className = mergeClasses( drawerOverlayClassNames.backdrop, - backdropMotionStyles.backdrop, + backdropStyles.backdrop, durationStyles[state.size], - state.backdropMotion.active && backdropMotionStyles.visible, + state.backdropMotion.active && backdropStyles.visible, backdrop.className, ); } diff --git a/packages/react-components/react-drawer/src/shared/useDrawerBaseStyles.styles.ts b/packages/react-components/react-drawer/src/shared/useDrawerBaseStyles.styles.ts index 85e96d626dcbc..40fec51ab36a0 100644 --- a/packages/react-components/react-drawer/src/shared/useDrawerBaseStyles.styles.ts +++ b/packages/react-components/react-drawer/src/shared/useDrawerBaseStyles.styles.ts @@ -14,20 +14,19 @@ export const drawerCSSVars = { * Default shared styles for the Drawer component */ export const drawerDefaultStyles: GriffelStyle = { - ...shorthands.padding(0), ...shorthands.overflow('hidden'), - ...shorthands.borderRadius(0), - ...shorthands.border(0), width: `var(${drawerCSSVars.drawerSizeVar})`, maxWidth: '100vw', height: 'auto', + maxHeight: '100vh', boxSizing: 'border-box', display: 'flex', flexDirection: 'column', alignItems: 'flex-start', justifyContent: 'flex-start', backgroundColor: tokens.colorNeutralBackground1, + color: tokens.colorNeutralForeground1, }; /** diff --git a/packages/react-components/react-drawer/stories/Drawer/DrawerMotionCustom.stories.tsx b/packages/react-components/react-drawer/stories/Drawer/DrawerMotionCustom.stories.tsx index e2945107876a8..8900ff3e84728 100644 --- a/packages/react-components/react-drawer/stories/Drawer/DrawerMotionCustom.stories.tsx +++ b/packages/react-components/react-drawer/stories/Drawer/DrawerMotionCustom.stories.tsx @@ -4,18 +4,6 @@ import { Button, makeStyles, mergeClasses, shorthands, tokens } from '@fluentui/ import { Dismiss24Regular } from '@fluentui/react-icons'; import { useMotion } from '@fluentui/react-motion-preview'; -const visibleKeyframe = { - ...shorthands.borderRadius(0), - opacity: 1, - transform: 'translate3D(0, 0, 0) scale(1)', -}; - -const hiddenKeyframe = { - ...shorthands.borderRadius('36px'), - opacity: 0, - transform: 'translate3D(-100%, 0, 0) scale(0.5)', -}; - const useStyles = makeStyles({ root: { ...shorthands.border('2px', 'solid', '#ccc'), @@ -27,24 +15,23 @@ const useStyles = makeStyles({ }, drawer: { - animationDuration: tokens.durationGentle, - willChange: 'opacity, transform, border-radius', + opacity: 0, + transform: 'translate3D(-100%, 0, 0)', + transitionDuration: tokens.durationGentle, + willChange: 'opacity, transform', + }, + + drawerVisible: { + opacity: 1, + transform: 'translate3D(0, 0, 0)', }, drawerEntering: { - animationTimingFunction: tokens.curveDecelerateMid, - animationName: { - from: hiddenKeyframe, - to: visibleKeyframe, - }, + transitionTimingFunction: tokens.curveDecelerateMid, }, drawerExiting: { - animationTimingFunction: tokens.curveAccelerateMin, - animationName: { - from: visibleKeyframe, - to: hiddenKeyframe, - }, + transitionTimingFunction: tokens.curveAccelerateMin, }, content: { @@ -80,8 +67,8 @@ const useStyles = makeStyles({ export const MotionCustom = () => { const styles = useStyles(); - const [isOpen, setIsOpen] = React.useState(false); - const motion = useMotion(isOpen); + const [open, setOpen] = React.useState(false); + const motion = useMotion(open); return (
@@ -90,6 +77,7 @@ export const MotionCustom = () => { open={motion} className={mergeClasses( styles.drawer, + motion.active && styles.drawerVisible, motion.type === 'entering' && styles.drawerEntering, motion.type === 'exiting' && styles.drawerExiting, )} @@ -101,7 +89,7 @@ export const MotionCustom = () => { appearance="subtle" aria-label="Close" icon={} - onClick={() => setIsOpen(false)} + onClick={() => setOpen(false)} /> } > @@ -123,8 +111,8 @@ export const MotionCustom = () => { motion.type === 'idle' && styles.contentIdle, )} > - {Array.from({ length: 50 }, (_, i) => ( @@ -143,9 +131,9 @@ MotionCustom.parameters = { docs: { description: { story: [ - 'Drawer components have transition animations built-in. However, you can customize the animation by using the `useMotion` hook.', + 'Drawer components have motion built-in. However, you can customize the animation by using the `useMotion` hook.', 'The hook returns properties that can be used to determine the state of the animation, and can be passed to the `open` prop of the drawer.', - 'With this, you can create your own custom CSS animation and apply it to the drawer.', + 'With this, you can create your own custom CSS animation/transition and apply it to the drawer.', ].join('\n'), }, },