Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(react-drawer): allow aside tag for Drawer components #31434

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@
{
marcosmoura marked this conversation as resolved.
Show resolved Hide resolved
"type": "minor",
"comment": "feat: allow aside as tag for Drawer components",
"packageName": "@fluentui/react-drawer",
"email": "marcosvmmoura@gmail.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "fix: compatibility with Drawer slots",
"packageName": "@fluentui/react-nav-preview",
"email": "marcosvmmoura@gmail.com",
"dependentChangeType": "patch"
}
14 changes: 6 additions & 8 deletions packages/react-components/react-drawer/etc/react-drawer.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,13 @@ export type DrawerHeaderTitleState = ComponentState<DrawerHeaderTitleSlots>;
// @public
export type DrawerProps = ComponentProps<DrawerSlots> & {
type?: 'inline' | 'overlay';
};
} & (OverlayDrawerProps | InlineDrawerProps);

// @public (undocumented)
export const DrawerProvider: React_2.Provider<DrawerContextValue | undefined>;

// @public (undocumented)
export type DrawerSlots = {
root: Slot<OverlayDrawerProps | InlineDrawerProps>;
};
export type DrawerSlots = OverlayDrawerSlots | InlineDrawerSlots;

// @public
export type DrawerState = ComponentState<DrawerSlots>;
Expand All @@ -145,7 +143,7 @@ export type InlineDrawerProps = ComponentProps<InlineDrawerSlots> & DrawerBasePr

// @public (undocumented)
export type InlineDrawerSlots = {
root: Slot<'div'>;
root: Slot<'div', 'aside'>;
};

// @public
Expand All @@ -168,7 +166,7 @@ export type OverlayDrawerSlots = {
};

// @public
export type OverlayDrawerState = Omit<ComponentState<OverlayDrawerInternalSlots>, 'backdrop'> & Required<DrawerBaseState>;
export type OverlayDrawerState = ComponentState<OverlayDrawerInternalSlots> & Required<DrawerBaseState>;

// @public
export const renderDrawer_unstable: (state: DrawerState, contextValue: DrawerContextValue) => JSX.Element;
Expand Down Expand Up @@ -237,13 +235,13 @@ export const useDrawerHeaderTitleStyles_unstable: (state: DrawerHeaderTitleState
export const useDrawerStyles_unstable: (state: DrawerState) => DrawerState;

// @public
export const useInlineDrawer_unstable: (props: InlineDrawerProps, ref: React_2.Ref<HTMLDivElement>) => InlineDrawerState;
export const useInlineDrawer_unstable: (props: InlineDrawerProps, ref: React_2.Ref<HTMLElement>) => InlineDrawerState;

// @public
export const useInlineDrawerStyles_unstable: (state: InlineDrawerState) => InlineDrawerState;

// @public
export const useOverlayDrawer_unstable: (props: OverlayDrawerProps, ref: React_2.Ref<HTMLDivElement>) => OverlayDrawerState;
export const useOverlayDrawer_unstable: (props: OverlayDrawerProps, ref: React_2.Ref<HTMLElement>) => OverlayDrawerState;

// @public
export const useOverlayDrawerStyles_unstable: (state: OverlayDrawerState) => OverlayDrawerState;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe('Drawer', () => {
* component-handles-classname|component-has-static-classnames-object|make-styles-overrides-win: Drawer uses the DialogSurface component to render the classname, so the main component do not handle classname.
* consistent-callback-args: Disabled that as the Drawer callback function uses the same signature as the Dialog, and Dialog has those tests disabled.
*/
isConformant({
isConformant<DrawerProps>({
Component: Drawer,
displayName: 'Drawer',
disabledTests: [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import type { ComponentProps, ComponentState } from '@fluentui/react-utilities';

import type { OverlayDrawerProps } from '../OverlayDrawer';
import type { InlineDrawerProps } from '../InlineDrawer';
import type { OverlayDrawerProps, OverlayDrawerSlots } from '../OverlayDrawer';
import type { InlineDrawerProps, InlineDrawerSlots } from '../InlineDrawer';

export type DrawerSlots = {
/**
* Root slot of the Drawer.
*/
root: Slot<OverlayDrawerProps | InlineDrawerProps>;
};
export type DrawerSlots = OverlayDrawerSlots | InlineDrawerSlots;

/**
* Drawer Props
Expand All @@ -23,7 +18,7 @@ export type DrawerProps = ComponentProps<DrawerSlots> & {
* @default overlay
*/
type?: 'inline' | 'overlay';
};
} & (OverlayDrawerProps | InlineDrawerProps);

/**
* State used in rendering Drawer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ export const useDrawer_unstable = (props: DrawerProps, ref: React.Ref<HTMLElemen
root: elementType,
},

root: slot.always<DrawerProps>(
slot.resolveShorthand({
root: slot.always(
{
ref,
...props,
}),
},
{
elementType,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import * as React from 'react';
import { render } from '@testing-library/react';
import { InlineDrawer } from './InlineDrawer';
import { isConformant } from '../../testing/isConformant';
import { InlineDrawerProps } from './InlineDrawer.types';

describe('InlineDrawer', () => {
isConformant({
isConformant<InlineDrawerProps>({
Component: InlineDrawer,
displayName: 'InlineDrawer',
requiredProps: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utili
import { DrawerBaseProps, DrawerBaseState } from '../../shared/DrawerBase.types';

export type InlineDrawerSlots = {
root: Slot<'div'>;
root: Slot<'div', 'aside'>;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,11 @@ import { useDrawerDefaultProps } from '../../shared/useDrawerDefaultProps';
* @param props - props from this instance of InlineDrawer
* @param ref - reference to root HTMLElement of InlineDrawer
*/
export const useInlineDrawer_unstable = (
props: InlineDrawerProps,
ref: React.Ref<HTMLDivElement>,
): InlineDrawerState => {
export const useInlineDrawer_unstable = (props: InlineDrawerProps, ref: React.Ref<HTMLElement>): InlineDrawerState => {
const { size, position, open } = useDrawerDefaultProps(props);
const { separator = false } = props;

const motion = useMotion<HTMLDivElement>(open);
const motion = useMotion<HTMLElement>(open);

return {
components: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('OverlayDrawer', () => {
* component-handles-classname|component-has-static-classnames-object|make-styles-overrides-win: OverlayDrawer uses the DialogSurface component to render the className, so the main component do not handle className.
* consistent-callback-args: Disabled that as the OverlayDrawer callback function uses the same signature as the Dialog, and Dialog has those tests disabled.
*/
isConformant({
isConformant<OverlayDrawerProps>({
Component: OverlayDrawer,
displayName: 'OverlayDrawer',
disabledTests: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,4 @@ export type OverlayDrawerProps = ComponentProps<OverlayDrawerSlots> &
/**
* State used in rendering OverlayDrawer
*/
export type OverlayDrawerState = Omit<ComponentState<OverlayDrawerInternalSlots>, 'backdrop'> &
Required<DrawerBaseState>;
export type OverlayDrawerState = ComponentState<OverlayDrawerInternalSlots> & Required<DrawerBaseState>;
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,19 @@ import type { OverlayDrawerSurfaceProps } from './OverlayDrawerSurface.types';
* OverlayDrawerSurface is a proxy for DialogSurface as is only meant to be used internally for Drawer.
*/
export const OverlayDrawerSurface: ForwardRefComponent<OverlayDrawerSurfaceProps> = React.forwardRef((props, ref) => {
const dialogSurfaceState = useDialogSurface_unstable(props, ref);
const dialogSurfaceState = useDialogSurface_unstable(
{
...props,
/**
* Drawer accepts a `div` or `aside` element type, but Dialog only accepts a `div` element type.
* We need to cast the ref to a `div` element type to not break Dialog's ref type.
*
* FIXME: Evaluate the possibility to remove this cast when Dialog is refactored to accept `aside` elements.
*/
as: props.as as 'div',
marcosmoura marked this conversation as resolved.
Show resolved Hide resolved
},
ref,
);
const dialogSurfaceContextValues = useDialogSurfaceContextValues_unstable(dialogSurfaceState);

useOverlayDrawerSurfaceStyles_unstable(dialogSurfaceState);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import type { DialogSurfaceProps, DialogSurfaceSlots, DialogSurfaceState } from '@fluentui/react-dialog';
import type { ComponentState } from '@fluentui/react-utilities';
import type { DialogSurfaceProps, DialogSurfaceSlots } from '@fluentui/react-dialog';
import type { ComponentProps, Slot } from '@fluentui/react-utilities';

/**
* OverlayDrawerSurface slots
*/
export type OverlayDrawerSurfaceSlots = DialogSurfaceSlots;
export type OverlayDrawerSurfaceSlots = Pick<DialogSurfaceSlots, 'backdrop'> & {
root: Slot<'div', 'aside'>;
};

/**
* OverlayDrawerSurface Props
*/
export type OverlayDrawerSurfaceProps = DialogSurfaceProps;

/**
* State used in rendering OverlayDrawerSurface
*/
export type OverlayDrawerSurfaceState = ComponentState<OverlayDrawerSurfaceSlots> & DialogSurfaceState;
export type OverlayDrawerSurfaceProps = ComponentProps<OverlayDrawerSurfaceSlots> &
marcosmoura marked this conversation as resolved.
Show resolved Hide resolved
Pick<DialogSurfaceProps, 'mountNode'>;
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { makeResetStyles, makeStyles, mergeClasses } from '@griffel/react';
import type { SlotClassNames } from '@fluentui/react-utilities';
import { tokens } from '@fluentui/react-theme';
import { DialogSurfaceState } from '@fluentui/react-dialog';

import type { OverlayDrawerSurfaceSlots, OverlayDrawerSurfaceState } from './OverlayDrawerSurface.types';
import type { OverlayDrawerSurfaceSlots } from './OverlayDrawerSurface.types';

export const OverlayDrawerSurfaceClassNames: SlotClassNames<OverlayDrawerSurfaceSlots> = {
root: 'fui-OverlayDrawerSurface',
Expand All @@ -27,7 +28,7 @@ const useBackdropStyles = makeStyles({
/**
* Apply styling to the OverlayDrawerSurface slots based on the state
*/
export const useOverlayDrawerSurfaceStyles_unstable = (state: OverlayDrawerSurfaceState): OverlayDrawerSurfaceState => {
export const useOverlayDrawerSurfaceStyles_unstable = (state: DialogSurfaceState): DialogSurfaceState => {
const backdropResetStyles = useBackdropResetStyles();
const backdropStyles = useBackdropStyles();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,32 @@ import { OverlayDrawerSurface } from './OverlayDrawerSurface';
* before being passed to renderOverlayDrawer_unstable.
*
* @param props - props from this instance of OverlayDrawer
* @param ref - reference to root HTMLDivElement of OverlayDrawer
* @param ref - reference to root HTMLElement of OverlayDrawer
*/
export const useOverlayDrawer_unstable = (
props: OverlayDrawerProps,
ref: React.Ref<HTMLDivElement>,
ref: React.Ref<HTMLElement>,
): OverlayDrawerState => {
const { open, size, position } = useDrawerDefaultProps(props);
const { modalType = 'modal', inertTrapFocus, onOpenChange } = props;

const motion = useMotion<HTMLDivElement>(open);
const motion = useMotion<HTMLElement>(open);

const backdropProps = slot.resolveShorthand(props.backdrop);
const hasCustomBackdrop = modalType !== 'non-modal' && backdropProps !== null;

const root = slot.always(
{
...props,
ref: useMergedRefs(ref, motion.ref),
backdrop: hasCustomBackdrop ? { ...backdropProps } : null,
},
{
elementType: OverlayDrawerSurface,
defaultProps: {
ref: useMergedRefs(ref, motion.ref),
},
/**
* Drawer accepts a `div` or `aside` element type, but Dialog only accepts a `div` element type.
* We need to cast the ref to a `div` element type to not break Dialog's ref type.
*/
elementType: OverlayDrawerSurface as unknown as 'div',
},
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export type DrawerBaseProps = {
};

export type DrawerBaseState = Required<Pick<DrawerBaseProps, 'position' | 'size'>> & {
motion: MotionState<HTMLDivElement>;
motion: MotionState<HTMLElement>;
};

export type DrawerScrollState = 'none' | 'top' | 'middle' | 'bottom';
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,21 @@ const useStyles = makeStyles({
},
});

type DrawerInlineExampleProps = {
open: boolean;
type DrawerInlineExampleProps = DrawerProps & {
setOpen: (open: boolean) => void;
position: DrawerProps['position'];
};

const getMappedPosition = (position: DrawerProps['position']) => {
switch (position) {
case 'end':
return 'Right';

case 'bottom':
return 'Bottom';

default:
return 'Left';
}
};

const setButtonText = (open: boolean, position: DrawerProps['position']) => {
Expand All @@ -80,16 +91,16 @@ const setButtonText = (open: boolean, position: DrawerProps['position']) => {
return buttonText;
};

const DrawerInlineExample: React.FC<DrawerInlineExampleProps> = ({ open, setOpen, position }) => {
const DrawerInlineExample: React.FC<DrawerInlineExampleProps> = ({ setOpen, ...props }) => {
return (
<InlineDrawer open={open} position={position}>
<InlineDrawer {...props}>
<DrawerHeader>
<DrawerHeaderTitle
action={
<Button appearance="subtle" aria-label="Close" icon={<Dismiss24Regular />} onClick={() => setOpen(false)} />
}
>
{position} Inline Drawer
{getMappedPosition(props.position)} Inline Drawer
</DrawerHeaderTitle>
</DrawerHeader>

Expand All @@ -110,7 +121,7 @@ export const Inline = () => {
return (
<div className={mergeClasses(styles.root, styles.flexColumn)}>
<div className={styles.root}>
<DrawerInlineExample open={leftOpen} setOpen={setLeftOpen} position="start" />
<DrawerInlineExample as="aside" open={leftOpen} setOpen={setLeftOpen} position="start" />

<div className={styles.content}>
<div className={styles.buttons}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const Overlay = () => {

return (
<div>
<OverlayDrawer open={isOpen} onOpenChange={(_, { open }) => setIsOpen(open)}>
<OverlayDrawer as="aside" open={isOpen} onOpenChange={(_, { open }) => setIsOpen(open)}>
<DrawerHeader>
<DrawerHeaderTitle
action={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { ARIAButtonSlotProps } from '@fluentui/react-aria';
import { ButtonProps } from '@fluentui/react-button';
import { ButtonSlots } from '@fluentui/react-button';
import { ButtonState } from '@fluentui/react-button';
import type { ComponentProps } from '@fluentui/react-utilities';
import { ComponentProps } from '@fluentui/react-utilities';
import type { ComponentState } from '@fluentui/react-utilities';
import type { DrawerBodyProps } from '@fluentui/react-drawer';
import type { DrawerBodySlots } from '@fluentui/react-drawer';
Expand All @@ -25,6 +25,7 @@ import type { DrawerHeaderProps } from '@fluentui/react-drawer';
import type { DrawerHeaderSlots } from '@fluentui/react-drawer';
import type { DrawerHeaderState } from '@fluentui/react-drawer';
import { DrawerProps } from '@fluentui/react-drawer';
import { DrawerSlots } from '@fluentui/react-drawer';
import { DrawerState } from '@fluentui/react-drawer';
import type { EventData } from '@fluentui/react-utilities';
import { EventHandler } from '@fluentui/react-utilities';
Expand Down Expand Up @@ -173,7 +174,10 @@ export type NavDrawerHeaderSlots = DrawerHeaderSlots;
export type NavDrawerHeaderState = DrawerHeaderState;

// @public
export type NavDrawerProps = DrawerProps & NavProps;
export type NavDrawerProps = ComponentProps<NavDrawerSlots> & DrawerProps & NavProps;

// @public
export type NavDrawerSlots = DrawerSlots;

// @public
export type NavDrawerState = DrawerState & NavContextValue;
Expand Down
Loading
Loading