diff --git a/change/@fluentui-react-provider-8d16b583-90bc-4602-8f12-908adfa27fa2.json b/change/@fluentui-react-provider-8d16b583-90bc-4602-8f12-908adfa27fa2.json new file mode 100644 index 00000000000000..a760b5babf1dd7 --- /dev/null +++ b/change/@fluentui-react-provider-8d16b583-90bc-4602-8f12-908adfa27fa2.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat: add style overrides for drawer components", + "packageName": "@fluentui/react-provider", + "email": "marcosvmmoura@gmail.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-shared-contexts-9885d20c-9563-4217-9582-4dea3020602a.json b/change/@fluentui-react-shared-contexts-9885d20c-9563-4217-9582-4dea3020602a.json new file mode 100644 index 00000000000000..961ac6a2eb37ab --- /dev/null +++ b/change/@fluentui-react-shared-contexts-9885d20c-9563-4217-9582-4dea3020602a.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat: add style overrides for drawer components", + "packageName": "@fluentui/react-shared-contexts", + "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 28dcbac986b6f1..2c2299c1873542 100644 --- a/packages/react-components/react-drawer/etc/react-drawer.api.md +++ b/packages/react-components/react-drawer/etc/react-drawer.api.md @@ -10,6 +10,7 @@ import type { ComponentProps } from '@fluentui/react-utilities'; import type { ComponentState } from '@fluentui/react-utilities'; import type { DialogProps } from '@fluentui/react-dialog'; import type { DialogSurfaceProps } from '@fluentui/react-dialog'; +import { DialogTitleSlots } from '@fluentui/react-dialog'; import type { ForwardRefComponent } from '@fluentui/react-utilities'; import * as React_2 from 'react'; import type { Slot } from '@fluentui/react-utilities'; @@ -25,7 +26,7 @@ export const DrawerBody: ForwardRefComponent; export const drawerBodyClassNames: SlotClassNames; // @public -export type DrawerBodyProps = ComponentProps & {}; +export type DrawerBodyProps = ComponentProps; // @public (undocumented) export type DrawerBodySlots = { @@ -61,6 +62,61 @@ export type DrawerFooterSlots = { // @public export type DrawerFooterState = ComponentState; +// @public +export const DrawerHeader: ForwardRefComponent; + +// @public (undocumented) +export const drawerHeaderClassNames: SlotClassNames; + +// @public +export const DrawerHeaderNavigation: ForwardRefComponent; + +// @public (undocumented) +export const drawerHeaderNavigationClassNames: SlotClassNames; + +// @public +export type DrawerHeaderNavigationProps = ComponentProps; + +// @public (undocumented) +export type DrawerHeaderNavigationSlots = { + root: Slot<'nav'>; +}; + +// @public +export type DrawerHeaderNavigationState = ComponentState; + +// @public +export type DrawerHeaderProps = ComponentProps; + +// @public (undocumented) +export type DrawerHeaderSlots = { + root: Slot<'header'>; +}; + +// @public +export type DrawerHeaderState = ComponentState; + +// @public +export const DrawerHeaderTitle: ForwardRefComponent; + +// @public (undocumented) +export const drawerHeaderTitleClassNames: SlotClassNames; + +// @public +export type DrawerHeaderTitleProps = ComponentProps & { + children: React_2.ReactNode | undefined; +}; + +// @public (undocumented) +export type DrawerHeaderTitleSlots = { + root: Slot<'div'>; + heading?: DialogTitleSlots['root']; + action?: DialogTitleSlots['action']; +}; + +// @public +export type DrawerHeaderTitleState = ComponentState; + // @public export type DrawerProps = ComponentProps> & { position?: 'left' | 'right'; @@ -91,6 +147,15 @@ export const renderDrawerBody_unstable: (state: DrawerBodyState) => JSX.Element; // @public export const renderDrawerFooter_unstable: (state: DrawerFooterState) => JSX.Element; +// @public +export const renderDrawerHeader_unstable: (state: DrawerHeaderState) => JSX.Element; + +// @public +export const renderDrawerHeaderNavigation_unstable: (state: DrawerHeaderNavigationState) => JSX.Element; + +// @public +export const renderDrawerHeaderTitle_unstable: (state: DrawerHeaderTitleState) => JSX.Element; + // @public export const useDrawer_unstable: (props: DrawerProps, ref: React_2.Ref) => DrawerState; @@ -106,6 +171,24 @@ export const useDrawerFooter_unstable: (props: DrawerFooterProps, ref: React_2.R // @public export const useDrawerFooterStyles_unstable: (state: DrawerFooterState) => DrawerFooterState; +// @public +export const useDrawerHeader_unstable: (props: DrawerHeaderProps, ref: React_2.Ref) => DrawerHeaderState; + +// @public +export const useDrawerHeaderNavigation_unstable: (props: DrawerHeaderNavigationProps, ref: React_2.Ref) => DrawerHeaderNavigationState; + +// @public +export const useDrawerHeaderNavigationStyles_unstable: (state: DrawerHeaderNavigationState) => DrawerHeaderNavigationState; + +// @public +export const useDrawerHeaderStyles_unstable: (state: DrawerHeaderState) => DrawerHeaderState; + +// @public +export const useDrawerHeaderTitle_unstable: (props: DrawerHeaderTitleProps, ref: React_2.Ref) => DrawerHeaderTitleState; + +// @public +export const useDrawerHeaderTitleStyles_unstable: (state: DrawerHeaderTitleState) => DrawerHeaderTitleState; + // @public export const useDrawerStyles_unstable: (state: DrawerState) => DrawerState; diff --git a/packages/react-components/react-drawer/src/DrawerHeader.ts b/packages/react-components/react-drawer/src/DrawerHeader.ts new file mode 100644 index 00000000000000..633e9bd67e1ed9 --- /dev/null +++ b/packages/react-components/react-drawer/src/DrawerHeader.ts @@ -0,0 +1 @@ +export * from './components/DrawerHeader/index'; diff --git a/packages/react-components/react-drawer/src/DrawerHeaderNavigation.ts b/packages/react-components/react-drawer/src/DrawerHeaderNavigation.ts new file mode 100644 index 00000000000000..6ee42495974f5e --- /dev/null +++ b/packages/react-components/react-drawer/src/DrawerHeaderNavigation.ts @@ -0,0 +1 @@ +export * from './components/DrawerHeaderNavigation/index'; diff --git a/packages/react-components/react-drawer/src/DrawerHeaderTitle.ts b/packages/react-components/react-drawer/src/DrawerHeaderTitle.ts new file mode 100644 index 00000000000000..c24ec49aaecc0b --- /dev/null +++ b/packages/react-components/react-drawer/src/DrawerHeaderTitle.ts @@ -0,0 +1 @@ +export * from './components/DrawerHeaderTitle/index'; 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 e79b8e3a26fa6c..952d27ac35169f 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 @@ -45,8 +45,8 @@ export type DrawerProps = ComponentProps> & { /** * When this is set, the rest of the page is dimmed out and cannot be interacted with. - * The tab sequence is kept within the dialog and moving the focus outside - * the dialog will imply closing it. This is the default type of the component. + * The tab sequence is kept within the drawer and moving the focus outside + * the drawer will imply closing it. This is the default type of the component. * This prop is only used when `type` is `overlay`. * * @defaultvalue true diff --git a/packages/react-components/react-drawer/src/components/Drawer/useDrawerStyles.styles.ts b/packages/react-components/react-drawer/src/components/Drawer/useDrawerStyles.styles.ts index 0cb0c9d2d1f64e..92ee01f77776c3 100644 --- a/packages/react-components/react-drawer/src/components/Drawer/useDrawerStyles.styles.ts +++ b/packages/react-components/react-drawer/src/components/Drawer/useDrawerStyles.styles.ts @@ -20,14 +20,15 @@ export const drawerCSSVars = { */ const useStyles = makeStyles({ root: { + ...shorthands.padding(0), + ...shorthands.overflow('hidden'), ...shorthands.borderRadius(`var(${drawerCSSVars.borderRadius})`), ...shorthands.border(0), - ...shorthands.overflow('hidden'), [drawerCSSVars.borderRadius]: 0, width: `var(${drawerCSSVars.size})`, - maxWidth: 'calc(100vw - 48px)', + maxWidth: '100vw', height: 'auto', boxSizing: 'border-box', display: 'flex', diff --git a/packages/react-components/react-drawer/src/components/DrawerBody/DrawerBody.types.ts b/packages/react-components/react-drawer/src/components/DrawerBody/DrawerBody.types.ts index 6497c736411f28..ed36f16c208806 100644 --- a/packages/react-components/react-drawer/src/components/DrawerBody/DrawerBody.types.ts +++ b/packages/react-components/react-drawer/src/components/DrawerBody/DrawerBody.types.ts @@ -7,7 +7,7 @@ export type DrawerBodySlots = { /** * DrawerBody Props */ -export type DrawerBodyProps = ComponentProps & {}; +export type DrawerBodyProps = ComponentProps; /** * State used in rendering DrawerBody diff --git a/packages/react-components/react-drawer/src/components/DrawerBody/useDrawerBodyStyles.styles.ts b/packages/react-components/react-drawer/src/components/DrawerBody/useDrawerBodyStyles.styles.ts index 9c5b84dc3109b9..9aa1907af02c7b 100644 --- a/packages/react-components/react-drawer/src/components/DrawerBody/useDrawerBodyStyles.styles.ts +++ b/packages/react-components/react-drawer/src/components/DrawerBody/useDrawerBodyStyles.styles.ts @@ -17,6 +17,8 @@ const useStyles = makeStyles({ ...shorthands.overflow('auto'), ...shorthands.flex(1), + alignSelf: 'stretch', + // A "good hack" to display top and bottom borders based on the scroll position backgroundImage: `linear-gradient(to top, ${tokens.colorNeutralBackground1}, ${tokens.colorNeutralBackground1}), linear-gradient(to top, ${tokens.colorNeutralBackground1}, ${tokens.colorNeutralBackground1}), diff --git a/packages/react-components/react-drawer/src/components/DrawerHeader/DrawerHeader.test.tsx b/packages/react-components/react-drawer/src/components/DrawerHeader/DrawerHeader.test.tsx new file mode 100644 index 00000000000000..ec373900e090ed --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeader/DrawerHeader.test.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import { render } from '@testing-library/react'; +import { DrawerHeader } from './DrawerHeader'; +import { isConformant } from '../../testing/isConformant'; + +describe('DrawerHeader', () => { + isConformant({ + Component: DrawerHeader, + displayName: 'DrawerHeader', + }); + + it('renders a default state', () => { + const result = render(Default DrawerHeader); + expect(result.container).toMatchInlineSnapshot(` +
+
+ Default DrawerHeader +
+
+ `); + }); +}); diff --git a/packages/react-components/react-drawer/src/components/DrawerHeader/DrawerHeader.tsx b/packages/react-components/react-drawer/src/components/DrawerHeader/DrawerHeader.tsx new file mode 100644 index 00000000000000..cb5d7cb5a0e076 --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeader/DrawerHeader.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; +import { useDrawerHeader_unstable } from './useDrawerHeader'; +import { renderDrawerHeader_unstable } from './renderDrawerHeader'; +import { useDrawerHeaderStyles_unstable } from './useDrawerHeaderStyles'; +import type { DrawerHeaderProps } from './DrawerHeader.types'; +import type { ForwardRefComponent } from '@fluentui/react-utilities'; +import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts'; + +/** + * DrawerHeader provides a structured header for the drawer component. + */ +export const DrawerHeader: ForwardRefComponent = React.forwardRef((props, ref) => { + const state = useDrawerHeader_unstable(props, ref); + + useDrawerHeaderStyles_unstable(state); + useCustomStyleHook_unstable('useDrawerHeaderStyles_unstable')(state); + + return renderDrawerHeader_unstable(state); +}); + +DrawerHeader.displayName = 'DrawerHeader'; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeader/DrawerHeader.types.ts b/packages/react-components/react-drawer/src/components/DrawerHeader/DrawerHeader.types.ts new file mode 100644 index 00000000000000..411d1507b9ff3d --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeader/DrawerHeader.types.ts @@ -0,0 +1,18 @@ +import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities'; + +export type DrawerHeaderSlots = { + /** + * The root of the DrawerHeader. + */ + root: Slot<'header'>; +}; + +/** + * DrawerHeader Props + */ +export type DrawerHeaderProps = ComponentProps; + +/** + * State used in rendering DrawerHeader + */ +export type DrawerHeaderState = ComponentState; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeader/index.ts b/packages/react-components/react-drawer/src/components/DrawerHeader/index.ts new file mode 100644 index 00000000000000..acb991359954c9 --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeader/index.ts @@ -0,0 +1,5 @@ +export * from './DrawerHeader'; +export * from './DrawerHeader.types'; +export * from './renderDrawerHeader'; +export * from './useDrawerHeader'; +export * from './useDrawerHeaderStyles'; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeader/renderDrawerHeader.tsx b/packages/react-components/react-drawer/src/components/DrawerHeader/renderDrawerHeader.tsx new file mode 100644 index 00000000000000..abbad67ac71f59 --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeader/renderDrawerHeader.tsx @@ -0,0 +1,12 @@ +import * as React from 'react'; +import { getSlots } from '@fluentui/react-utilities'; +import type { DrawerHeaderState, DrawerHeaderSlots } from './DrawerHeader.types'; + +/** + * Render the final JSX of DrawerHeader + */ +export const renderDrawerHeader_unstable = (state: DrawerHeaderState) => { + const { slots, slotProps } = getSlots(state); + + return ; +}; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeader/useDrawerHeader.ts b/packages/react-components/react-drawer/src/components/DrawerHeader/useDrawerHeader.ts new file mode 100644 index 00000000000000..76eb8a39308422 --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeader/useDrawerHeader.ts @@ -0,0 +1,25 @@ +import * as React from 'react'; +import { getNativeElementProps } from '@fluentui/react-utilities'; +import type { DrawerHeaderProps, DrawerHeaderState } from './DrawerHeader.types'; + +/** + * Create the state required to render DrawerHeader. + * + * The returned state can be modified with hooks such as useDrawerHeaderStyles_unstable, + * before being passed to renderDrawerHeader_unstable. + * + * @param props - props from this instance of DrawerHeader + * @param ref - reference to root HTMLElement of DrawerHeader + */ +export const useDrawerHeader_unstable = (props: DrawerHeaderProps, ref: React.Ref): DrawerHeaderState => { + return { + components: { + root: 'header', + }, + + root: getNativeElementProps('header', { + ref, + ...props, + }), + }; +}; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeader/useDrawerHeaderStyles.ts b/packages/react-components/react-drawer/src/components/DrawerHeader/useDrawerHeaderStyles.ts new file mode 100644 index 00000000000000..700254c4dd7aa6 --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeader/useDrawerHeaderStyles.ts @@ -0,0 +1,33 @@ +import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; +import type { DrawerHeaderSlots, DrawerHeaderState } from './DrawerHeader.types'; +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { tokens } from '@fluentui/react-theme'; + +export const drawerHeaderClassNames: SlotClassNames = { + root: 'fui-DrawerHeader', +}; + +/** + * Styles for the root slot + */ +const useStyles = makeStyles({ + root: { + ...shorthands.padding(tokens.spacingVerticalXXL, tokens.spacingHorizontalXXL, tokens.spacingVerticalS), + ...shorthands.gap(tokens.spacingHorizontalS), + + alignSelf: 'stretch', + display: 'flex', + flexDirection: 'column', + }, +}); + +/** + * Apply styling to the DrawerHeader slots based on the state + */ +export const useDrawerHeaderStyles_unstable = (state: DrawerHeaderState): DrawerHeaderState => { + const styles = useStyles(); + + state.root.className = mergeClasses(drawerHeaderClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/DrawerHeaderNavigation.test.tsx b/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/DrawerHeaderNavigation.test.tsx new file mode 100644 index 00000000000000..fe50ca0fef8d9a --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/DrawerHeaderNavigation.test.tsx @@ -0,0 +1,26 @@ +import * as React from 'react'; +import { render } from '@testing-library/react'; +import { DrawerHeaderNavigation } from './DrawerHeaderNavigation'; +import { isConformant } from '../../testing/isConformant'; + +describe('DrawerHeaderNavigation', () => { + isConformant({ + Component: DrawerHeaderNavigation, + displayName: 'DrawerHeaderNavigation', + }); + + // TODO add more tests here, and create visual regression tests in /apps/vr-tests + + it('renders a default state', () => { + const result = render(Default DrawerHeaderNavigation); + expect(result.container).toMatchInlineSnapshot(` +
+ +
+ `); + }); +}); diff --git a/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/DrawerHeaderNavigation.tsx b/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/DrawerHeaderNavigation.tsx new file mode 100644 index 00000000000000..1cfabb2d0e505c --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/DrawerHeaderNavigation.tsx @@ -0,0 +1,23 @@ +import * as React from 'react'; +import { useDrawerHeaderNavigation_unstable } from './useDrawerHeaderNavigation'; +import { renderDrawerHeaderNavigation_unstable } from './renderDrawerHeaderNavigation'; +import { useDrawerHeaderNavigationStyles_unstable } from './useDrawerHeaderNavigationStyles.styles'; +import type { DrawerHeaderNavigationProps } from './DrawerHeaderNavigation.types'; +import type { ForwardRefComponent } from '@fluentui/react-utilities'; +import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts'; + +/** + * DrawerHeaderNavigation provides a header navigation area for the Drawer. + */ +export const DrawerHeaderNavigation: ForwardRefComponent = React.forwardRef( + (props, ref) => { + const state = useDrawerHeaderNavigation_unstable(props, ref); + + useDrawerHeaderNavigationStyles_unstable(state); + useCustomStyleHook_unstable('useDrawerHeaderNavigationStyles_unstable')(state); + + return renderDrawerHeaderNavigation_unstable(state); + }, +); + +DrawerHeaderNavigation.displayName = 'DrawerHeaderNavigation'; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/DrawerHeaderNavigation.types.ts b/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/DrawerHeaderNavigation.types.ts new file mode 100644 index 00000000000000..0deb06a6c4020a --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/DrawerHeaderNavigation.types.ts @@ -0,0 +1,15 @@ +import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities'; + +export type DrawerHeaderNavigationSlots = { + root: Slot<'nav'>; +}; + +/** + * DrawerHeaderNavigation Props + */ +export type DrawerHeaderNavigationProps = ComponentProps; + +/** + * State used in rendering DrawerHeaderNavigation + */ +export type DrawerHeaderNavigationState = ComponentState; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/index.ts b/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/index.ts new file mode 100644 index 00000000000000..9324533810264c --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/index.ts @@ -0,0 +1,5 @@ +export * from './DrawerHeaderNavigation'; +export * from './DrawerHeaderNavigation.types'; +export * from './renderDrawerHeaderNavigation'; +export * from './useDrawerHeaderNavigation'; +export * from './useDrawerHeaderNavigationStyles.styles'; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/renderDrawerHeaderNavigation.tsx b/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/renderDrawerHeaderNavigation.tsx new file mode 100644 index 00000000000000..9f9d5bca765580 --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/renderDrawerHeaderNavigation.tsx @@ -0,0 +1,12 @@ +import * as React from 'react'; +import { getSlots } from '@fluentui/react-utilities'; +import type { DrawerHeaderNavigationState, DrawerHeaderNavigationSlots } from './DrawerHeaderNavigation.types'; + +/** + * Render the final JSX of DrawerHeaderNavigation + */ +export const renderDrawerHeaderNavigation_unstable = (state: DrawerHeaderNavigationState) => { + const { slots, slotProps } = getSlots(state); + + return ; +}; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/useDrawerHeaderNavigation.ts b/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/useDrawerHeaderNavigation.ts new file mode 100644 index 00000000000000..4d8470d3d438cf --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/useDrawerHeaderNavigation.ts @@ -0,0 +1,28 @@ +import * as React from 'react'; +import { getNativeElementProps } from '@fluentui/react-utilities'; +import type { DrawerHeaderNavigationProps, DrawerHeaderNavigationState } from './DrawerHeaderNavigation.types'; + +/** + * Create the state required to render DrawerHeaderNavigation. + * + * The returned state can be modified with hooks such as useDrawerHeaderNavigationStyles_unstable, + * before being passed to renderDrawerHeaderNavigation_unstable. + * + * @param props - props from this instance of DrawerHeaderNavigation + * @param ref - reference to root HTMLElement of DrawerHeaderNavigation + */ +export const useDrawerHeaderNavigation_unstable = ( + props: DrawerHeaderNavigationProps, + ref: React.Ref, +): DrawerHeaderNavigationState => { + return { + components: { + root: 'nav', + }, + + root: getNativeElementProps('nav', { + ref, + ...props, + }), + }; +}; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/useDrawerHeaderNavigationStyles.styles.ts b/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/useDrawerHeaderNavigationStyles.styles.ts new file mode 100644 index 00000000000000..56b91579518260 --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeaderNavigation/useDrawerHeaderNavigationStyles.styles.ts @@ -0,0 +1,32 @@ +import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; +import type { DrawerHeaderNavigationSlots, DrawerHeaderNavigationState } from './DrawerHeaderNavigation.types'; +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { tokens } from '@fluentui/react-theme'; + +export const drawerHeaderNavigationClassNames: SlotClassNames = { + root: 'fui-DrawerHeaderNavigation', +}; + +/** + * Styles for the root slot + */ +const useStyles = makeStyles({ + root: { + ...shorthands.margin(`calc(${tokens.spacingVerticalS} * -1)`, `calc(${tokens.spacingHorizontalL} * -1)`), + + order: 0, + }, +}); + +/** + * Apply styling to the DrawerHeaderNavigation slots based on the state + */ +export const useDrawerHeaderNavigationStyles_unstable = ( + state: DrawerHeaderNavigationState, +): DrawerHeaderNavigationState => { + const styles = useStyles(); + + state.root.className = mergeClasses(drawerHeaderNavigationClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/DrawerHeaderTitle.test.tsx b/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/DrawerHeaderTitle.test.tsx new file mode 100644 index 00000000000000..fa2554dd5d1eea --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/DrawerHeaderTitle.test.tsx @@ -0,0 +1,69 @@ +import * as React from 'react'; +import { render } from '@testing-library/react'; +import { DrawerHeaderTitle } from './DrawerHeaderTitle'; +import { isConformant } from '../../testing/isConformant'; +import { DrawerHeaderTitleProps } from './DrawerHeaderTitle.types'; +import { drawerHeaderTitleClassNames } from './useDrawerHeaderTitleStyles.styles'; + +describe('DrawerHeaderTitle', () => { + isConformant({ + Component: DrawerHeaderTitle, + displayName: 'DrawerHeaderTitle', + testOptions: { + 'has-static-classnames': [ + { + props: { + action: 'Action', + }, + expectedClassNames: { + root: drawerHeaderTitleClassNames.root, + heading: drawerHeaderTitleClassNames.heading, + action: drawerHeaderTitleClassNames.action, + }, + }, + ], + }, + disabledTests: ['component-has-static-classnames-object'], + }); + + // TODO add more tests here, and create visual regression tests in /apps/vr-tests + + it('renders a default state', () => { + const result = render(Default DrawerHeaderTitle); + expect(result.container).toMatchInlineSnapshot(` +
+
+

+ Default DrawerHeaderTitle +

+
+
+ `); + }); + + it('renders action', () => { + const result = render(Default DrawerHeaderTitle); + expect(result.container).toMatchInlineSnapshot(` +
+
+

+ Default DrawerHeaderTitle +

+
+ Test +
+
+
+ `); + }); +}); diff --git a/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/DrawerHeaderTitle.tsx b/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/DrawerHeaderTitle.tsx new file mode 100644 index 00000000000000..e56ca1e48ee357 --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/DrawerHeaderTitle.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; +import { useDrawerHeaderTitle_unstable } from './useDrawerHeaderTitle'; +import { renderDrawerHeaderTitle_unstable } from './renderDrawerHeaderTitle'; +import { useDrawerHeaderTitleStyles_unstable } from './useDrawerHeaderTitleStyles.styles'; +import type { DrawerHeaderTitleProps } from './DrawerHeaderTitle.types'; +import type { ForwardRefComponent } from '@fluentui/react-utilities'; +import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts'; + +/** + * DrawerHeader provides a structured header for the drawer component. + */ +export const DrawerHeaderTitle: ForwardRefComponent = React.forwardRef((props, ref) => { + const state = useDrawerHeaderTitle_unstable(props, ref); + + useDrawerHeaderTitleStyles_unstable(state); + useCustomStyleHook_unstable('useDrawerHeaderTitleStyles_unstable')(state); + + return renderDrawerHeaderTitle_unstable(state); +}); + +DrawerHeaderTitle.displayName = 'DrawerHeaderTitle'; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/DrawerHeaderTitle.types.ts b/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/DrawerHeaderTitle.types.ts new file mode 100644 index 00000000000000..7f5c8b4ce6c13c --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/DrawerHeaderTitle.types.ts @@ -0,0 +1,34 @@ +import { DialogTitleSlots } from '@fluentui/react-dialog'; +import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities'; +import * as React from 'react'; + +export type DrawerHeaderTitleSlots = { + root: Slot<'div'>; + + /** + * By default this is a h2, but can be any heading or div. + * If `div` is provided do not forget to also provide proper `role="heading"` and `aria-level` attributes + */ + heading?: DialogTitleSlots['root']; + + /** + * Action slot for the close button + */ + action?: DialogTitleSlots['action']; +}; + +/** + * DrawerHeaderTitle Props + */ +export type DrawerHeaderTitleProps = ComponentProps & { + /** + * Content of the DrawerHeaderTitle + * Children is mandatory because DrawerHeaderTitle is a wrapper component + */ + children: React.ReactNode | undefined; +}; + +/** + * State used in rendering DrawerHeaderTitle + */ +export type DrawerHeaderTitleState = ComponentState; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/index.ts b/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/index.ts new file mode 100644 index 00000000000000..7163625fb9169c --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/index.ts @@ -0,0 +1,5 @@ +export * from './DrawerHeaderTitle'; +export * from './DrawerHeaderTitle.types'; +export * from './renderDrawerHeaderTitle'; +export * from './useDrawerHeaderTitle'; +export * from './useDrawerHeaderTitleStyles.styles'; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/renderDrawerHeaderTitle.tsx b/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/renderDrawerHeaderTitle.tsx new file mode 100644 index 00000000000000..ddc27dbbc3628a --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/renderDrawerHeaderTitle.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import { getSlots } from '@fluentui/react-utilities'; +import type { DrawerHeaderTitleState, DrawerHeaderTitleSlots } from './DrawerHeaderTitle.types'; + +/** + * Render the final JSX of DrawerHeaderTitle + */ +export const renderDrawerHeaderTitle_unstable = (state: DrawerHeaderTitleState) => { + const { slots, slotProps } = getSlots(state); + + return ( + + {slots.heading && } + {slots.action && } + + ); +}; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/useDrawerHeaderTitle.ts b/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/useDrawerHeaderTitle.ts new file mode 100644 index 00000000000000..9421256dba2a48 --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/useDrawerHeaderTitle.ts @@ -0,0 +1,43 @@ +import * as React from 'react'; +import { getNativeElementProps, resolveShorthand } from '@fluentui/react-utilities'; +import type { DrawerHeaderTitleProps, DrawerHeaderTitleState } from './DrawerHeaderTitle.types'; +import { useDialogTitle_unstable } from '@fluentui/react-dialog'; + +/** + * Create the state required to render DrawerHeaderTitle. + * + * The returned state can be modified with hooks such as useDrawerHeaderTitleStyles_unstable, + * before being passed to renderDrawerHeaderTitle_unstable. + * + * @param props - props from this instance of DrawerHeaderTitle + * @param ref - reference to root HTMLElement of DrawerHeaderTitle + */ +export const useDrawerHeaderTitle_unstable = ( + props: DrawerHeaderTitleProps, + ref: React.Ref, +): DrawerHeaderTitleState => { + const { root: heading, action, components: titleComponents } = useDialogTitle_unstable(props, ref); + + return { + components: { + root: 'div', + heading: titleComponents.root, + action: titleComponents.action, + }, + + root: getNativeElementProps('div', { + ref, + ...props, + }), + heading: resolveShorthand(props.heading, { + required: true, + defaultProps: { + ...heading, + className: undefined, // remove className from heading + }, + }), + action: resolveShorthand(props.action, { + defaultProps: action, + }), + }; +}; diff --git a/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/useDrawerHeaderTitleStyles.styles.ts b/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/useDrawerHeaderTitleStyles.styles.ts new file mode 100644 index 00000000000000..e144fe41bc74d6 --- /dev/null +++ b/packages/react-components/react-drawer/src/components/DrawerHeaderTitle/useDrawerHeaderTitleStyles.styles.ts @@ -0,0 +1,57 @@ +import { makeStyles, mergeClasses } from '@griffel/react'; +import type { DrawerHeaderTitleSlots, DrawerHeaderTitleState } from './DrawerHeaderTitle.types'; +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { useDialogTitleStyles_unstable } from '@fluentui/react-dialog'; +import { tokens } from '@fluentui/react-theme'; + +export const drawerHeaderTitleClassNames: SlotClassNames = { + root: 'fui-DrawerHeaderTitle', + heading: 'fui-DrawerHeaderTitle__heading', + action: 'fui-DrawerHeaderTitle__action', +}; + +/** + * Styles for the root slot + */ +const useStyles = makeStyles({ + root: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + columnGap: tokens.spacingHorizontalS, + }, + + action: { + marginRight: `calc(${tokens.spacingHorizontalS} * -1)`, + }, +}); + +/** + * Apply styling to the DrawerHeaderTitle slots based on the state + */ +export const useDrawerHeaderTitleStyles_unstable = (state: DrawerHeaderTitleState): DrawerHeaderTitleState => { + const styles = useStyles(); + + const { heading: root = {}, action, components } = state; + + useDialogTitleStyles_unstable({ + components: { + root: components.heading, + action: components.action, + }, + root, + action, + }); + + state.root.className = mergeClasses(drawerHeaderTitleClassNames.root, styles.root, state.root.className); + + if (state.heading) { + state.heading.className = mergeClasses(drawerHeaderTitleClassNames.heading, state.heading.className); + } + + if (state.action) { + state.action.className = mergeClasses(drawerHeaderTitleClassNames.action, styles.action, state.action.className); + } + + return state; +}; diff --git a/packages/react-components/react-drawer/src/index.ts b/packages/react-components/react-drawer/src/index.ts index f92da13e278f38..5a17da4a72462f 100644 --- a/packages/react-components/react-drawer/src/index.ts +++ b/packages/react-components/react-drawer/src/index.ts @@ -6,8 +6,8 @@ export { useDrawerStyles_unstable, useDrawer_unstable, } from './Drawer'; - export type { DrawerProps, DrawerSlots, DrawerState } from './Drawer'; + export { DrawerBody, drawerBodyClassNames, @@ -17,6 +17,37 @@ export { } from './DrawerBody'; export type { DrawerBodyProps, DrawerBodySlots, DrawerBodyState } from './DrawerBody'; +export { + DrawerHeader, + drawerHeaderClassNames, + renderDrawerHeader_unstable, + useDrawerHeaderStyles_unstable, + useDrawerHeader_unstable, +} from './DrawerHeader'; +export type { DrawerHeaderProps, DrawerHeaderSlots, DrawerHeaderState } from './DrawerHeader'; + +export { + DrawerHeaderTitle, + drawerHeaderTitleClassNames, + renderDrawerHeaderTitle_unstable, + useDrawerHeaderTitleStyles_unstable, + useDrawerHeaderTitle_unstable, +} from './DrawerHeaderTitle'; +export type { DrawerHeaderTitleProps, DrawerHeaderTitleSlots, DrawerHeaderTitleState } from './DrawerHeaderTitle'; + +export { + DrawerHeaderNavigation, + drawerHeaderNavigationClassNames, + renderDrawerHeaderNavigation_unstable, + useDrawerHeaderNavigationStyles_unstable, + useDrawerHeaderNavigation_unstable, +} from './DrawerHeaderNavigation'; +export type { + DrawerHeaderNavigationProps, + DrawerHeaderNavigationSlots, + DrawerHeaderNavigationState, +} from './DrawerHeaderNavigation'; + export { DrawerFooter, drawerFooterClassNames, diff --git a/packages/react-components/react-drawer/stories/Drawer/DrawerAlwaysOpen.stories.tsx b/packages/react-components/react-drawer/stories/Drawer/DrawerAlwaysOpen.stories.tsx index 25e4528aaff8d6..3e14960ae1fc79 100644 --- a/packages/react-components/react-drawer/stories/Drawer/DrawerAlwaysOpen.stories.tsx +++ b/packages/react-components/react-drawer/stories/Drawer/DrawerAlwaysOpen.stories.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { Drawer } from '@fluentui/react-drawer'; +import { Drawer, DrawerBody, DrawerHeader, DrawerHeaderTitle } from '@fluentui/react-drawer'; import { makeStyles, shorthands } from '@fluentui/react-components'; const useStyles = makeStyles({ @@ -17,7 +17,6 @@ const useStyles = makeStyles({ display: 'flex', justifyContent: 'center', alignItems: 'flex-start', - backgroundColor: 'lightblue', }, }); @@ -26,8 +25,14 @@ export const AlwaysOpen = () => { return (
- -

Always open

+ + + Always open + + + +

Drawer content

+
diff --git a/packages/react-components/react-drawer/stories/Drawer/DrawerCustomSize.stories.tsx b/packages/react-components/react-drawer/stories/Drawer/DrawerCustomSize.stories.tsx index 4a9dba65ae3bda..0cfb404b05f135 100644 --- a/packages/react-components/react-drawer/stories/Drawer/DrawerCustomSize.stories.tsx +++ b/packages/react-components/react-drawer/stories/Drawer/DrawerCustomSize.stories.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; -import { Drawer } from '@fluentui/react-drawer'; +import { Drawer, DrawerBody, DrawerHeader, DrawerHeaderTitle } from '@fluentui/react-drawer'; import { Button, Label, useId, tokens, makeStyles, Input } from '@fluentui/react-components'; +import { Dismiss24Regular } from '@fluentui/react-icons'; const useStyles = makeStyles({ main: { @@ -21,7 +22,7 @@ export const CustomSize = () => { const inputId = useId('custom-size-label'); const [open, setOpen] = React.useState(false); - const [customSize, setCustomSize] = React.useState(250); + const [customSize, setCustomSize] = React.useState(600); return (
@@ -31,14 +32,24 @@ export const CustomSize = () => { onOpenChange={(_, state) => setOpen(state.open)} style={{ width: `${customSize}px` }} > - + + } + onClick={() => setOpen(false)} + /> + } + > + Drawer with {customSize}px size + + -

- Lorem ipsum dolor sit, amet consectetur adipisicing elit. Necessitatibus quod sint pariatur tempora assumenda - fugit, veniam harum architecto quisquam iure laboriosam, eum hic rem ea provident magnam error. Eum, eveniet. -

+ +

Drawer content

+
diff --git a/packages/react-components/react-drawer/stories/Drawer/DrawerDefault.stories.tsx b/packages/react-components/react-drawer/stories/Drawer/DrawerDefault.stories.tsx index 9ed625ce571153..1dd06445a01ccd 100644 --- a/packages/react-components/react-drawer/stories/Drawer/DrawerDefault.stories.tsx +++ b/packages/react-components/react-drawer/stories/Drawer/DrawerDefault.stories.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; -import { Drawer } from '@fluentui/react-drawer'; +import { Drawer, DrawerBody, DrawerHeader, DrawerHeaderTitle } from '@fluentui/react-drawer'; import { Button } from '@fluentui/react-components'; +import { Dismiss24Regular } from '@fluentui/react-icons'; export const Default = () => { const [isOpen, setIsOpen] = React.useState(false); @@ -8,11 +9,24 @@ export const Default = () => { return (
setIsOpen(open)}> - + + } + onClick={() => setIsOpen(false)} + /> + } + > + Default Drawer + + -

Drawer content

+ +

Drawer content

+
-

Open by default

- - -
- -
-
- ); -}; diff --git a/packages/react-components/react-drawer/stories/Drawer/DrawerInline.stories.tsx b/packages/react-components/react-drawer/stories/Drawer/DrawerInline.stories.tsx index 1eed381f281b9c..757a543a55caa3 100644 --- a/packages/react-components/react-drawer/stories/Drawer/DrawerInline.stories.tsx +++ b/packages/react-components/react-drawer/stories/Drawer/DrawerInline.stories.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; -import { Drawer } from '@fluentui/react-drawer'; +import { Drawer, DrawerBody, DrawerHeader, DrawerHeaderTitle } from '@fluentui/react-drawer'; import { Button, makeStyles, shorthands } from '@fluentui/react-components'; +import { Dismiss24Regular } from '@fluentui/react-icons'; const useStyles = makeStyles({ root: { @@ -29,10 +30,24 @@ export const Inline = () => { return (
setLeftOpen(open)}> - -

Left Drawer

+ + } + onClick={() => setLeftOpen(false)} + /> + } + > + Left Inline Drawer + + + + +

Drawer content

+
@@ -46,10 +61,24 @@ export const Inline = () => {
setRightOpen(open)}> - -

Right Drawer

+ + } + onClick={() => setRightOpen(false)} + /> + } + > + Right Inline Drawer + + + + +

Drawer content

+
); diff --git a/packages/react-components/react-drawer/stories/Drawer/DrawerPosition.stories.tsx b/packages/react-components/react-drawer/stories/Drawer/DrawerPosition.stories.tsx index 3a9fa813114f8a..9f2e6c0332f6de 100644 --- a/packages/react-components/react-drawer/stories/Drawer/DrawerPosition.stories.tsx +++ b/packages/react-components/react-drawer/stories/Drawer/DrawerPosition.stories.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; -import { Drawer } from '@fluentui/react-drawer'; +import { Drawer, DrawerBody, DrawerHeader, DrawerHeaderTitle } from '@fluentui/react-drawer'; import { Button } from '@fluentui/react-components'; +import { Dismiss24Regular } from '@fluentui/react-icons'; export const Position = () => { const [leftOpen, setLeftOpen] = React.useState(false); @@ -9,10 +10,24 @@ export const Position = () => { return (
setLeftOpen(open)}> - -

Left Drawer

+ + } + onClick={() => setLeftOpen(false)} + /> + } + > + Left Drawer + + + + +

Drawer content

+
setRightOpen(open)}> - -

Right Drawer

+ + } + onClick={() => setRightOpen(false)} + /> + } + > + Right Drawer + + + + +

Drawer content

+
); diff --git a/packages/react-components/react-drawer/stories/Drawer/DrawerPreventClose.stories.tsx b/packages/react-components/react-drawer/stories/Drawer/DrawerPreventClose.stories.tsx index 02d079a65bbd95..42298f12832c70 100644 --- a/packages/react-components/react-drawer/stories/Drawer/DrawerPreventClose.stories.tsx +++ b/packages/react-components/react-drawer/stories/Drawer/DrawerPreventClose.stories.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; -import { Drawer } from '@fluentui/react-drawer'; +import { Drawer, DrawerBody, DrawerHeader, DrawerHeaderTitle } from '@fluentui/react-drawer'; import { Button } from '@fluentui/react-components'; +import { Dismiss24Regular } from '@fluentui/react-icons'; export const PreventClose = () => { const [open, setOpen] = React.useState(false); @@ -8,10 +9,24 @@ export const PreventClose = () => { return (
- -

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

+ + } + onClick={() => setOpen(false)} + /> + } + > + Prevent close with Esc or outside click + + + + +

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

+
-

This drawer has no separator

+ + } + onClick={() => setLeftOpen(false)} + /> + } + > + Drawer with no separator + + + + +

Drawer content

+
@@ -58,10 +73,24 @@ export const Separator = () => { open={rightOpen} onOpenChange={(_, { open }) => setRightOpen(open)} > - -

This drawer has a separator

+ + } + onClick={() => setRightOpen(false)} + /> + } + > + Drawer with separator + + + + +

Drawer content

+
); diff --git a/packages/react-components/react-drawer/stories/Drawer/DrawerSize.stories.tsx b/packages/react-components/react-drawer/stories/Drawer/DrawerSize.stories.tsx index 13814b41ac6247..8e5bb5f15f4a77 100644 --- a/packages/react-components/react-drawer/stories/Drawer/DrawerSize.stories.tsx +++ b/packages/react-components/react-drawer/stories/Drawer/DrawerSize.stories.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; -import { Drawer, DrawerProps } from '@fluentui/react-drawer'; +import { Drawer, DrawerBody, DrawerHeader, DrawerHeaderTitle, DrawerProps } from '@fluentui/react-drawer'; import { Button, Label, RadioGroup, Radio, useId, tokens, makeStyles } from '@fluentui/react-components'; +import { Dismiss24Regular } from '@fluentui/react-icons'; const useStyles = makeStyles({ main: { @@ -15,24 +16,43 @@ const useStyles = makeStyles({ }, }); +type DrawerSizeStory = Required['size']; + export const Size = () => { const styles = useStyles(); const labelId = useId('size-label'); const [open, setOpen] = React.useState(false); - const [size, setSize] = React.useState('small'); + const [size, setSize] = React.useState('small'); + + const labelMap: Record = { + small: 'Small (Default)', + medium: 'Medium', + large: 'Large', + full: 'Full', + }; return (
setOpen(state.open)}> - + + } + onClick={() => setOpen(false)} + /> + } + > + {labelMap[size]} size + + -

- Lorem ipsum dolor sit, amet consectetur adipisicing elit. Necessitatibus quod sint pariatur tempora assumenda - fugit, veniam harum architecto quisquam iure laboriosam, eum hic rem ea provident magnam error. Eum, eveniet. -

+ +

Drawer content

+
@@ -44,13 +64,12 @@ export const Size = () => { setSize(data.value as DrawerProps['size'])} + onChange={(_, data) => setSize(data.value as DrawerSizeStory)} aria-labelledby={labelId} > - - - - + {Object.keys(labelMap).map(key => ( + + ))}
diff --git a/packages/react-components/react-drawer/stories/Drawer/DrawerWithNavigation.stories.tsx b/packages/react-components/react-drawer/stories/Drawer/DrawerWithNavigation.stories.tsx new file mode 100644 index 00000000000000..00fa8684ebe3b3 --- /dev/null +++ b/packages/react-components/react-drawer/stories/Drawer/DrawerWithNavigation.stories.tsx @@ -0,0 +1,54 @@ +import * as React from 'react'; +import { Drawer, DrawerBody, DrawerHeader, DrawerHeaderNavigation, DrawerHeaderTitle } from '@fluentui/react-drawer'; +import { Button, Toolbar, ToolbarGroup, ToolbarButton, makeStyles } from '@fluentui/react-components'; +import { Dismiss24Regular } from '@fluentui/react-icons'; +import { ArrowClockwise24Regular } from '@fluentui/react-icons'; +import { Settings24Regular } from '@fluentui/react-icons'; +import { ArrowLeft24Regular } from '@fluentui/react-icons'; + +const useStyles = makeStyles({ + toolbar: { + justifyContent: 'space-between', + }, +}); + +export const WithNavigation = () => { + const styles = useStyles(); + + const [isOpen, setIsOpen] = React.useState(false); + + return ( +
+ setIsOpen(open)}> + + + + } /> + + + } /> + } /> + } + onClick={() => setIsOpen(false)} + /> + + + + + Title goes here + + + +

Drawer content

+
+
+ + +
+ ); +}; diff --git a/packages/react-components/react-drawer/stories/DrawerBody/DrawerBodyDefault.stories.tsx b/packages/react-components/react-drawer/stories/Drawer/DrawerWithScroll.stories.tsx similarity index 73% rename from packages/react-components/react-drawer/stories/DrawerBody/DrawerBodyDefault.stories.tsx rename to packages/react-components/react-drawer/stories/Drawer/DrawerWithScroll.stories.tsx index 4a0862a16c28c4..998691bebfcdfd 100644 --- a/packages/react-components/react-drawer/stories/DrawerBody/DrawerBodyDefault.stories.tsx +++ b/packages/react-components/react-drawer/stories/Drawer/DrawerWithScroll.stories.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { Drawer, DrawerBody, DrawerBodyProps, DrawerFooter } from '@fluentui/react-drawer'; -import { Button, makeStyles, shorthands, tokens } from '@fluentui/react-components'; +import { Drawer, DrawerBody, DrawerHeader, DrawerHeaderTitle, DrawerFooter } from '@fluentui/react-drawer'; +import { Button, makeStyles } from '@fluentui/react-components'; const useStyles = makeStyles({ root: { @@ -10,24 +10,15 @@ const useStyles = makeStyles({ }, drawer: { - height: '300px', - }, - - container: { - ...shorthands.padding(tokens.spacingHorizontalXXL), - display: 'flex', - justifyContent: 'flex-start', - alignItems: 'center', + height: '400px', }, }); const Header = () => { - const styles = useStyles(); - return ( -
- This is a header -
+ + Title goes here + ); }; @@ -55,28 +46,28 @@ const Body = () => { ); }; -export const Default = (props: Partial) => { +export const WithScroll = () => { const styles = useStyles(); return (
- +
- + - +
- +
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 48f0c9d4d65b84..00357c2d4588a6 100644 --- a/packages/react-components/react-drawer/stories/Drawer/index.stories.tsx +++ b/packages/react-components/react-drawer/stories/Drawer/index.stories.tsx @@ -1,21 +1,28 @@ -import { Drawer } from '@fluentui/react-drawer'; +import { Drawer, DrawerBody, DrawerHeader, DrawerHeaderTitle, DrawerHeaderNavigation } from '@fluentui/react-drawer'; import descriptionMd from './DrawerDescription.md'; 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 { Separator } from './DrawerSeparator.stories'; +export { AlwaysOpen } from './DrawerAlwaysOpen.stories'; +export { PreventClose } from './DrawerPreventClose.stories'; +export { WithNavigation } from './DrawerWithNavigation.stories'; +export { WithScroll } from './DrawerWithScroll.stories'; export default { - title: 'Preview Components/Drawer/Drawer', + title: 'Preview Components/Drawer', component: Drawer, + subcomponents: { + DrawerBody, + DrawerHeader, + DrawerHeaderTitle, + DrawerHeaderNavigation, + }, parameters: { docs: { description: { diff --git a/packages/react-components/react-drawer/stories/DrawerBody/DrawerBodyBestPractices.md b/packages/react-components/react-drawer/stories/DrawerBody/DrawerBodyBestPractices.md deleted file mode 100644 index 08ff8ddeeb5f86..00000000000000 --- a/packages/react-components/react-drawer/stories/DrawerBody/DrawerBodyBestPractices.md +++ /dev/null @@ -1,5 +0,0 @@ -## Best practices - -### Do - -### Don't diff --git a/packages/react-components/react-drawer/stories/DrawerBody/DrawerBodyDescription.md b/packages/react-components/react-drawer/stories/DrawerBody/DrawerBodyDescription.md deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/packages/react-components/react-drawer/stories/DrawerBody/index.stories.tsx b/packages/react-components/react-drawer/stories/DrawerBody/index.stories.tsx deleted file mode 100644 index 296cf279db8c63..00000000000000 --- a/packages/react-components/react-drawer/stories/DrawerBody/index.stories.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { DrawerBody } from '@fluentui/react-drawer'; - -import descriptionMd from './DrawerBodyDescription.md'; -import bestPracticesMd from './DrawerBodyBestPractices.md'; - -export { Default } from './DrawerBodyDefault.stories'; - -export default { - title: 'Preview Components/DrawerBody', - component: DrawerBody, - parameters: { - docs: { - description: { - component: [descriptionMd, bestPracticesMd].join('\n'), - }, - }, - }, -}; diff --git a/packages/react-components/react-provider/etc/react-provider.api.md b/packages/react-components/react-provider/etc/react-provider.api.md index b7e2f50274ebb5..5936d3a195357f 100644 --- a/packages/react-components/react-provider/etc/react-provider.api.md +++ b/packages/react-components/react-provider/etc/react-provider.api.md @@ -107,6 +107,9 @@ export const FluentProvider: React_2.ForwardRefExoticComponent void; useDrawerStyles_unstable: (state: unknown) => void; useDrawerBodyStyles_unstable: (state: unknown) => void; + useDrawerHeaderStyles_unstable: (state: unknown) => void; + useDrawerHeaderTitleStyles_unstable: (state: unknown) => void; + useDrawerHeaderNavigationStyles_unstable: (state: unknown) => void; }> | undefined; dir?: "ltr" | "rtl" | undefined; targetDocument?: Document | undefined; diff --git a/packages/react-components/react-shared-contexts/etc/react-shared-contexts.api.md b/packages/react-components/react-shared-contexts/etc/react-shared-contexts.api.md index 34cfb47f5c4f08..ec1af62ae00e65 100644 --- a/packages/react-components/react-shared-contexts/etc/react-shared-contexts.api.md +++ b/packages/react-components/react-shared-contexts/etc/react-shared-contexts.api.md @@ -94,6 +94,9 @@ export const CustomStyleHooksContext_unstable: React_2.Context | undefined>; // @public (undocumented) @@ -183,6 +186,9 @@ export type CustomStyleHooksContextValue_unstable = Partial<{ useDataGridSelectionCellStyles_unstable: CustomStyleHook; useDrawerStyles_unstable: CustomStyleHook; useDrawerBodyStyles_unstable: CustomStyleHook; + useDrawerHeaderStyles_unstable: CustomStyleHook; + useDrawerHeaderTitleStyles_unstable: CustomStyleHook; + useDrawerHeaderNavigationStyles_unstable: CustomStyleHook; }>; // @internal (undocumented) @@ -272,6 +278,9 @@ export const CustomStyleHooksProvider_unstable: React_2.Provider | undefined>; // @internal (undocumented) diff --git a/packages/react-components/react-shared-contexts/src/CustomStyleHooksContext/CustomStyleHooksContext.ts b/packages/react-components/react-shared-contexts/src/CustomStyleHooksContext/CustomStyleHooksContext.ts index c0695054d26c97..a188ac5cb4b799 100644 --- a/packages/react-components/react-shared-contexts/src/CustomStyleHooksContext/CustomStyleHooksContext.ts +++ b/packages/react-components/react-shared-contexts/src/CustomStyleHooksContext/CustomStyleHooksContext.ts @@ -91,6 +91,9 @@ export type CustomStyleHooksContextValue = Partial<{ useDataGridSelectionCellStyles_unstable: CustomStyleHook; useDrawerStyles_unstable: CustomStyleHook; useDrawerBodyStyles_unstable: CustomStyleHook; + useDrawerHeaderStyles_unstable: CustomStyleHook; + useDrawerHeaderTitleStyles_unstable: CustomStyleHook; + useDrawerHeaderNavigationStyles_unstable: CustomStyleHook; }>; /**