Skip to content
Draft
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
7 changes: 7 additions & 0 deletions change/@fluentui-react-dialog-base-hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-react-components/Charts-DonutChart 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Charts-DonutChart.Dynamic.default.chromium.png 5581 Changed
vr-tests-react-components/Menu Converged - submenuIndicator slotted content 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default.submenus open.chromium.png 413 Changed
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default - RTL.submenus open.chromium.png 404 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.chromium.png 616 Changed
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 40 Changed
vr-tests-react-components/TagPicker 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/TagPicker.disabled.disabled input hover.chromium.png 677 Changed

There were 1 duplicate changes discarded. Check the build logs for more information.

"type": "minor",
"comment": "feat(react-dialog): add useDialogBase_unstable, useDialogSurfaceBase_unstable, and useDialogActionsBase_unstable hooks",
"packageName": "@fluentui/react-dialog",
"email": "dmytrokirpa@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ARIAButtonType } from '@fluentui/react-aria';
import type { ComponentProps } from '@fluentui/react-utilities';
import type { ComponentState } from '@fluentui/react-utilities';
import { ContextSelector } from '@fluentui/react-context-selector';
import type { DistributiveOmit } from '@fluentui/react-utilities';
import type { ExtractSlotProps } from '@fluentui/react-utilities';
import type { ForwardRefComponent } from '@fluentui/react-utilities';
import type { JSXElement } from '@fluentui/react-utilities';
Expand All @@ -35,6 +36,12 @@ export const DIALOG_MEDIA_QUERY_SHORT_SCREEN = "@media screen and (max-height: 3
// @public
export const DialogActions: ForwardRefComponent<DialogActionsProps>;

// @public
export type DialogActionsBaseProps = DistributiveOmit<DialogActionsProps, 'position' | 'fluid'>;

// @public
export type DialogActionsBaseState = ComponentState<DialogActionsSlots>;

// @public (undocumented)
export const dialogActionsClassNames: SlotClassNames<DialogActionsSlots>;

Expand Down Expand Up @@ -66,6 +73,15 @@ export type DialogBackdropSlotProps = ExtractSlotProps<Slot<'div'> & {
appearance?: 'dimmed' | 'transparent';
}>;

// @public
export type DialogBaseProps = ComponentProps<{}> & Omit<DialogProps, 'surfaceMotion'>;

// @public
export type DialogBaseState = ComponentState<Omit<InternalDialogSlots, 'surfaceMotion'>> & DialogContextValue & {
content: React_2.ReactNode;
trigger: React_2.ReactNode;
};

// @public
export const DialogBody: ForwardRefComponent<DialogBodyProps>;

Expand Down Expand Up @@ -158,7 +174,7 @@ export const DialogProvider: React_2.Provider<DialogContextValue | undefined> &

// @public (undocumented)
export type DialogSlots = {
surfaceMotion: Slot<PresenceMotionSlotProps>;
surfaceMotion?: Slot<PresenceMotionSlotProps>;
};

// @public (undocumented)
Expand All @@ -170,6 +186,17 @@ export type DialogState = ComponentState<InternalDialogSlots> & DialogContextVal
// @public
export const DialogSurface: ForwardRefComponent<DialogSurfaceProps>;

// @public
export type DialogSurfaceBaseProps = ComponentProps<Omit<DialogSurfaceSlots, 'backdropMotion'>> & Pick<PortalProps, 'mountNode'>;

// @public
export type DialogSurfaceBaseState = ComponentState<Omit<DialogSurfaceSlots, 'backdropMotion'>> & Pick<DialogContextValue, 'isNestedDialog'> & Pick<PortalProps, 'mountNode'> & {
open?: boolean;
unmountOnClose?: boolean;
treatBackdropAsNested: boolean;
backdropAppearance?: DialogBackdropSlotProps['appearance'];
};

// @public (undocumented)
export const dialogSurfaceClassNames: SlotClassNames<Omit<DialogSurfaceSlots, 'backdropMotion'>>;

Expand All @@ -194,7 +221,7 @@ export const DialogSurfaceProvider: React_2.Provider<boolean | undefined>;
export type DialogSurfaceSlots = {
backdrop?: Slot<DialogBackdropSlotProps>;
root: Slot<'div'>;
backdropMotion: Slot<PresenceMotionSlotProps>;
backdropMotion?: Slot<PresenceMotionSlotProps>;
};

// @public
Expand Down Expand Up @@ -250,7 +277,7 @@ export type DialogTriggerState = {
export const renderDialog_unstable: (state: DialogState, contextValues: DialogContextValues) => JSXElement;

// @public
export const renderDialogActions_unstable: (state: DialogActionsState) => JSXElement;
export const renderDialogActions_unstable: (state: DialogActionsBaseState) => JSXElement;

// @public
export const renderDialogBody_unstable: (state: DialogBodyState) => JSXElement;
Expand All @@ -259,7 +286,7 @@ export const renderDialogBody_unstable: (state: DialogBodyState) => JSXElement;
export const renderDialogContent_unstable: (state: DialogContentState) => JSXElement;

// @public
export const renderDialogSurface_unstable: (state: DialogSurfaceState, contextValues: DialogSurfaceContextValues) => JSXElement;
export const renderDialogSurface_unstable: (state: DialogSurfaceBaseState, contextValues: DialogSurfaceContextValues) => JSXElement;

// @public
export const renderDialogTitle_unstable: (state: DialogTitleState) => JSXElement;
Expand All @@ -273,12 +300,18 @@ export const useDialog_unstable: (props: DialogProps) => DialogState;
// @public
export const useDialogActions_unstable: (props: DialogActionsProps, ref: React_2.Ref<HTMLElement>) => DialogActionsState;

// @public
export const useDialogActionsBase_unstable: (props: DialogActionsBaseProps, ref: React_2.Ref<HTMLElement>) => DialogActionsBaseState;

// @public
export const useDialogActionsStyles_unstable: (state: DialogActionsState) => DialogActionsState;

// @public (undocumented)
export const useDialogBackdropContext_unstable: () => DialogBackdropContextValue | undefined;

// @public
export const useDialogBase_unstable: (props: DialogBaseProps) => DialogBaseState;

// @public
export const useDialogBody_unstable: (props: DialogBodyProps, ref: React_2.Ref<HTMLElement>) => DialogBodyState;

Expand All @@ -300,6 +333,9 @@ export function useDialogContextValues_unstable(state: DialogState): DialogConte
// @public
export const useDialogSurface_unstable: (props: DialogSurfaceProps, ref: React_2.Ref<DialogSurfaceElement>) => DialogSurfaceState;

// @public
export const useDialogSurfaceBase_unstable: (props: DialogSurfaceBaseProps, ref: React_2.Ref<DialogSurfaceElement>) => DialogSurfaceBaseState;

// @public (undocumented)
export const useDialogSurfaceContext_unstable: () => DialogSurfaceContextValue;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export type {
DialogBaseProps,
DialogBaseState,
DialogContextValues,
DialogModalType,
DialogOpenChangeData,
Expand All @@ -14,4 +16,5 @@ export {
renderDialog_unstable,
useDialogContextValues_unstable,
useDialog_unstable,
useDialogBase_unstable,
} from './components/Dialog/index';
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export type {
DialogActionsBaseProps,
DialogActionsBaseState,
DialogActionsPosition,
DialogActionsProps,
DialogActionsSlots,
Expand All @@ -10,4 +12,5 @@ export {
renderDialogActions_unstable,
useDialogActionsStyles_unstable,
useDialogActions_unstable,
useDialogActionsBase_unstable,
} from './components/DialogActions/index';
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export type {
DialogBackdropSlotProps,
DialogSurfaceBaseProps,
DialogSurfaceBaseState,
DialogSurfaceContextValues,
DialogSurfaceElement,
DialogSurfaceProps,
Expand All @@ -13,4 +15,5 @@ export {
useDialogSurfaceContextValues_unstable,
useDialogSurfaceStyles_unstable,
useDialogSurface_unstable,
useDialogSurfaceBase_unstable,
} from './components/DialogSurface/index';
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type DialogSlots = {
* For more information refer to the [Motion docs page](https://react.fluentui.dev/?path=/docs/motion-motion-slot--docs).
*
*/
surfaceMotion: Slot<PresenceMotionSlotProps>;
surfaceMotion?: Slot<PresenceMotionSlotProps>;
};

export type InternalDialogSlots = {
Expand Down Expand Up @@ -122,3 +122,18 @@ export type DialogState = ComponentState<InternalDialogSlots> &
content: React.ReactNode;
trigger: React.ReactNode;
};

/**
* Dialog props without design-specific props (i.e. `surfaceMotion`).
* Use with `useDialogBase_unstable` to build custom-styled Dialog variants.
*/
export type DialogBaseProps = ComponentProps<{}> & Omit<DialogProps, 'surfaceMotion'>;

/**
* Dialog state without design-specific state fields (no `surfaceMotion`).
*/
export type DialogBaseState = ComponentState<Omit<InternalDialogSlots, 'surfaceMotion'>> &
DialogContextValue & {
content: React.ReactNode;
trigger: React.ReactNode;
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export { Dialog } from './Dialog';
export type {
DialogBaseProps,
DialogBaseState,
DialogContextValues,
DialogModalType,
DialogOpenChangeData,
Expand All @@ -11,5 +13,5 @@ export type {
InternalDialogSlots,
} from './Dialog.types';
export { renderDialog_unstable } from './renderDialog';
export { useDialog_unstable } from './useDialog';
export { useDialog_unstable, useDialogBase_unstable } from './useDialog';
export { useDialogContextValues_unstable } from './useDialogContextValues';
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,32 @@ import * as React from 'react';

import { MotionRefForwarder } from '@fluentui/react-motion';
import { DialogProvider, DialogSurfaceProvider } from '../../contexts';
import type { DialogState, DialogContextValues, InternalDialogSlots } from './Dialog.types';
import type { DialogState, DialogContextValues, DialogSlots } from './Dialog.types';

/**
* Render the final JSX of Dialog
*/
export const renderDialog_unstable = (state: DialogState, contextValues: DialogContextValues): JSXElement => {
assertSlots<InternalDialogSlots>(state);
assertSlots<DialogSlots>(state);

return (
<DialogProvider value={contextValues.dialog}>
<DialogSurfaceProvider value={contextValues.dialogSurface}>
{state.trigger}
{state.content && (
<state.surfaceMotion>
<MotionRefForwarder>
{/* Casting here as content should be equivalent to <DialogSurface/> */}
{/* FIXME: content should not be ReactNode it should be ReactElement instead. */}
{state.content as React.ReactElement}
</MotionRefForwarder>
</state.surfaceMotion>
)}
{state.content &&
(state.surfaceMotion ? (
<state.surfaceMotion>
<MotionRefForwarder>
{/* Casting here as content should be equivalent to <DialogSurface/> */}
{/* FIXME: content should not be ReactNode it should be ReactElement instead. */}
{state.content as React.ReactElement}
</MotionRefForwarder>
</state.surfaceMotion>
) : (
/* Casting here as content should be equivalent to <DialogSurface/> */
/* FIXME: content should not be ReactNode it should be ReactElement instead. */
(state.content as React.ReactElement)
))}
</DialogSurfaceProvider>
</DialogProvider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import { useControllableState, useEventCallback, useId } from '@fluentui/react-u
import { useFocusFirstElement } from '../../utils';
import { DialogContext } from '../../contexts';
import { DialogSurfaceMotion } from '../DialogSurfaceMotion';
import type { DialogOpenChangeData, DialogProps, DialogState } from './Dialog.types';
import type { DialogBaseProps, DialogBaseState, DialogOpenChangeData, DialogProps, DialogState } from './Dialog.types';

/**
* Create the state required to render Dialog.
* Create the base state required to render Dialog without design-specific props.
*
* The returned state can be modified with hooks such as useDialogStyles_unstable,
* before being passed to renderDialog_unstable.
* The returned state can be composed with `useDialog_unstable` or used directly
* to build custom-styled Dialog variants.
*
* @param props - props from this instance of Dialog
* @param props - props from this instance of Dialog (without surfaceMotion)
*/
export const useDialog_unstable = (props: DialogProps): DialogState => {
export const useDialogBase_unstable = (props: DialogBaseProps): DialogBaseState => {
const { children, modalType = 'modal', onOpenChange, inertTrapFocus = false, unmountOnClose = true } = props;

const dialogTitleId = useId('dialog-title-');
Expand Down Expand Up @@ -53,9 +53,7 @@ export const useDialog_unstable = (props: DialogProps): DialogState => {
const isNestedDialog = useHasParentContext(DialogContext);

return {
components: {
surfaceMotion: DialogSurfaceMotion,
},
components: {},
inertTrapFocus,
open,
modalType,
Expand All @@ -68,10 +66,30 @@ export const useDialog_unstable = (props: DialogProps): DialogState => {
dialogRef,
modalAttributes,
triggerAttributes,
};
};

/**
* Create the state required to render Dialog.
*
* The returned state can be modified with hooks such as useDialogStyles_unstable,
* before being passed to renderDialog_unstable.
*
* @param props - props from this instance of Dialog
*/
export const useDialog_unstable = (props: DialogProps): DialogState => {
const state = useDialogBase_unstable(props);
const unmountOnClose = props.unmountOnClose ?? true;

return {
...state,
components: {
surfaceMotion: DialogSurfaceMotion,
},
surfaceMotion: presenceMotionSlot(props.surfaceMotion, {
elementType: DialogSurfaceMotion,
defaultProps: {
visible: open,
visible: state.open,
appear: unmountOnClose,
unmountOnExit: unmountOnClose,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import type { ComponentProps, ComponentState, DistributiveOmit, Slot } from '@fluentui/react-utilities';

export type DialogActionsSlots = {
root: Slot<'div'>;
Expand Down Expand Up @@ -28,3 +28,14 @@ export type DialogActionsProps = ComponentProps<DialogActionsSlots> & {
*/
export type DialogActionsState = ComponentState<DialogActionsSlots> &
Pick<Required<DialogActionsProps>, 'position' | 'fluid'>;

/**
* DialogActions props without design-specific props (`position` and `fluid`).
* Use with `useDialogActionsBase_unstable` to build custom-styled DialogActions variants.
*/
export type DialogActionsBaseProps = DistributiveOmit<DialogActionsProps, 'position' | 'fluid'>;

/**
* DialogActions state without design-specific state fields (no `position` or `fluid`).
*/
export type DialogActionsBaseState = ComponentState<DialogActionsSlots>;
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
export { DialogActions } from './DialogActions';
export type {
DialogActionsBaseProps,
DialogActionsBaseState,
DialogActionsPosition,
DialogActionsProps,
DialogActionsSlots,
DialogActionsState,
} from './DialogActions.types';
export { renderDialogActions_unstable } from './renderDialogActions';
export { useDialogActions_unstable } from './useDialogActions';
export { useDialogActions_unstable, useDialogActionsBase_unstable } from './useDialogActions';
export { dialogActionsClassNames, useDialogActionsStyles_unstable } from './useDialogActionsStyles.styles';
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

import { assertSlots } from '@fluentui/react-utilities';
import type { JSXElement } from '@fluentui/react-utilities';
import type { DialogActionsState, DialogActionsSlots } from './DialogActions.types';
import type { DialogActionsBaseState, DialogActionsSlots } from './DialogActions.types';

/**
* Render the final JSX of DialogActions
*/
export const renderDialogActions_unstable = (state: DialogActionsState): JSXElement => {
export const renderDialogActions_unstable = (state: DialogActionsBaseState): JSXElement => {
assertSlots<DialogActionsSlots>(state);

// TODO Add additional slots in the appropriate place
Expand Down
Loading
Loading