Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8af5416
feat(react-drawer): make dialog slot to be used for composition only
marcosmoura Sep 25, 2023
322eb4b
fix: change type
marcosmoura Sep 25, 2023
368edcb
Merge branch 'master' into feat/react-drawer/make-dialog-slot-interna…
marcosmoura Sep 25, 2023
770b998
feat: create abstraction over DialogSurface
marcosmoura Sep 25, 2023
a2a52bf
fix: merge backdrop refs
marcosmoura Sep 25, 2023
6f6329d
fix: generate API
marcosmoura Sep 25, 2023
7593b14
fix: add outline styles
marcosmoura Sep 25, 2023
e7e1660
fix: rename nested var
marcosmoura Sep 25, 2023
642f459
Merge branch 'master' into feat/react-drawer/drawer-overlay-surface
marcosmoura Sep 26, 2023
b3701aa
fix: unify component, state and renderization
marcosmoura Oct 4, 2023
dfbfaf0
fix: rename variable
marcosmoura Oct 4, 2023
166130a
fix: wrong imports and types
marcosmoura Oct 4, 2023
ce59ebf
fix: add changefile
marcosmoura Oct 4, 2023
48344c2
fix: use token instead of hardcoded style
marcosmoura Oct 4, 2023
4d7c927
Merge branch 'master' into feat/react-drawer/drawer-overlay-surface
marcosmoura Oct 4, 2023
9e28ae6
Discard changes to packages/react-components/react-dialog/src/compone…
marcosmoura Oct 5, 2023
fcfd86d
Discard changes to packages/react-components/react-dialog/src/index.ts
marcosmoura Oct 5, 2023
3ffc170
Discard changes to packages/react-components/react-dialog/etc/react-d…
marcosmoura Oct 5, 2023
dbfedaa
Discard changes to packages/react-components/react-dialog/src/compone…
marcosmoura Oct 5, 2023
06d4251
Merge branch 'master' into feat/react-drawer/drawer-overlay-surface
marcosmoura Oct 5, 2023
5d87fbf
fix: use values already present on dialog state
marcosmoura Oct 5, 2023
1477140
fix: remove duplicated backdrop class name
marcosmoura Oct 5, 2023
13a20d6
Discard changes to change/@fluentui-react-dialog-04ca4ed5-a856-4939-b…
marcosmoura Oct 5, 2023
e0af5ed
fix: dependency mismatch
marcosmoura Oct 5, 2023
be009b7
Merge branch 'master' into feat/react-drawer/drawer-overlay-surface
marcosmoura Oct 5, 2023
8960a49
fix: generate API
marcosmoura Oct 5, 2023
325e42d
fix: use tokens for transparent colors
marcosmoura Oct 6, 2023
5f49913
fix: unify style in order to minimize atomic classes
marcosmoura Oct 6, 2023
f298094
fix: cypress tests
marcosmoura Oct 6, 2023
0183421
fix: improve types and generate API file
marcosmoura Oct 6, 2023
4d0a102
fix: dependency mismatch
marcosmoura Oct 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "feat: make dialog slot internal to be used for composition only",
"packageName": "@fluentui/react-drawer",
"email": "[email protected]",
"dependentChangeType": "patch"
}
16 changes: 7 additions & 9 deletions packages/react-components/react-drawer/etc/react-drawer.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -131,19 +130,18 @@ export type DrawerInlineState = Required<ComponentState<DrawerInlineSlots> & Dra
export const DrawerOverlay: ForwardRefComponent<DrawerOverlayProps>;

// @public (undocumented)
export const drawerOverlayClassNames: Omit<SlotClassNames<DrawerOverlaySlots>, 'dialog'>;
export const drawerOverlayClassNames: SlotClassNames<DrawerOverlaySurfaceSlots>;

// @public
export type DrawerOverlayProps = ComponentProps<DrawerOverlaySlots> & Pick<DialogProps, 'modalType' | 'onOpenChange' | 'inertTrapFocus' | 'defaultOpen'> & DrawerBaseProps;

// @public (undocumented)
export type DrawerOverlaySlots = DialogSurfaceSlots & {
root: Slot<DialogSurfaceProps>;
dialog?: Slot<DialogProps>;
// @public
export type DrawerOverlaySlots = {
root: Slot<DrawerOverlaySurfaceProps>;
};

// @public
export type DrawerOverlayState = Omit<ComponentState<DrawerOverlaySlots>, 'backdrop'> & Required<DrawerBaseState & {
export type DrawerOverlayState = Omit<ComponentState<DrawerOverlayInternalSlots>, 'backdrop'> & Required<DrawerBaseState & {
backdropMotion: MotionState<HTMLDivElement>;
}>;

Expand Down
9 changes: 5 additions & 4 deletions packages/react-components/react-drawer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@
"@fluentui/scripts-cypress": "*"
},
"dependencies": {
"@fluentui/react-dialog": "^9.7.5",
"@fluentui/react-jsx-runtime": "^9.0.13",
"@fluentui/react-motion-preview": "^0.2.10",
"@fluentui/react-dialog": "^9.7.6",
"@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.0",
"@fluentui/react-utilities": "^9.14.1",
"@griffel/react": "^1.5.14",
"@swc/helpers": "^0.5.1"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLElement>): DrawerState => {
const { type = 'overlay' } = props;

const elementType = type === 'overlay' ? DrawerOverlay : DrawerInline;
const elementType = props.type === 'inline' ? DrawerInline : DrawerOverlay;

return {
components: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(<FluentProvider theme={webLightTheme}>{element}</FluentProvider>);
Expand All @@ -28,14 +28,14 @@ describe('DrawerOverlay', () => {
it('should render backdrop', () => {
mountFluent(<ExampleDrawer />);

cy.get(`.${dialogSurfaceClassNames.backdrop}`).should('exist');
cy.get(`.${drawerOverlayClassNames.backdrop}`).should('exist');
});

it('should close when backdrop is clicked', () => {
mountFluent(<ExampleDrawer />);

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');
});
});
Expand All @@ -44,14 +44,14 @@ describe('DrawerOverlay', () => {
it('should render backdrop', () => {
mountFluent(<ExampleDrawer modalType="alert" />);

cy.get(`.${dialogSurfaceClassNames.backdrop}`).should('exist');
cy.get(`.${drawerOverlayClassNames.backdrop}`).should('exist');
});

it('should not close when backdrop is clicked', () => {
mountFluent(<ExampleDrawer modalType="alert" />);

cy.get('#drawer').should('exist');
cy.get(`.${dialogSurfaceClassNames.backdrop}`).click({ force: true });
cy.get(`.${drawerOverlayClassNames.backdrop}`).click({ force: true });
cy.get('#drawer').should('exist');
});
});
Expand All @@ -60,7 +60,7 @@ describe('DrawerOverlay', () => {
it('should not render backdrop when modalType is default', () => {
mountFluent(<ExampleDrawer modalType="non-modal" />);

cy.get(`.${dialogSurfaceClassNames.backdrop}`).should('not.exist');
cy.get(`.${drawerOverlayClassNames.backdrop}`).should('not.exist');
});
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -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<DialogSurfaceProps>;
/**
* DrawerOverlay slots
*/
export type DrawerOverlaySlots = {
/**
* Slot for the root element.
*/
root: Slot<DrawerOverlaySurfaceProps>;
};

/**
* DrawerOverlay internal slots for when using with composition API
*/
export type DrawerOverlayInternalSlots = DrawerOverlaySlots & {
/**
* Slot for the dialog component that wraps the drawer.
*/
dialog?: Slot<DialogProps>;
dialog: Slot<DialogProps>;
};

/**
Expand All @@ -23,9 +35,12 @@ export type DrawerOverlayProps = ComponentProps<DrawerOverlaySlots> &
/**
* State used in rendering DrawerOverlay
*/
export type DrawerOverlayState = Omit<ComponentState<DrawerOverlaySlots>, 'backdrop'> &
export type DrawerOverlayState = Omit<ComponentState<DrawerOverlayInternalSlots>, 'backdrop'> &
Required<
DrawerBaseState & {
/**
* Motion state for the drawer backdrop.
*/
backdropMotion: MotionState<HTMLDivElement>;
}
>;
Original file line number Diff line number Diff line change
@@ -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<DrawerOverlaySurfaceProps> = 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';
Original file line number Diff line number Diff line change
@@ -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<DrawerOverlaySurfaceSlots>;

/**
* State used in rendering DrawerOverlaySurface
*/
export type DrawerOverlaySurfaceState = ComponentState<DrawerOverlaySurfaceSlots> & DialogSurfaceState;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './DrawerOverlaySurface';
export * from './DrawerOverlaySurface.types';
Original file line number Diff line number Diff line change
@@ -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<DrawerOverlaySurfaceSlots> = {
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;
};
Original file line number Diff line number Diff line change
Expand Up @@ -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<DrawerOverlaySlots>(state);
assertSlots<DrawerOverlayInternalSlots>(state);

return (
<state.dialog>
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -25,44 +26,48 @@ export const useDrawerOverlay_unstable = (
const drawerMotion = useMotion<HTMLDivElement>(open);
const backdropMotion = useMotion<HTMLDivElement>(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,
Expand Down
Loading