Skip to content
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 @@
{
"type": "prerelease",
"comment": "feat: removes DialogSurface native dialog support ",
"packageName": "@fluentui/react-dialog",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export type DialogSurfaceProps = Omit<ComponentProps<DialogSurfaceSlots>, 'open'
// @public (undocumented)
export type DialogSurfaceSlots = {
backdrop?: Slot<'div'>;
root: NonNullable<Slot<'dialog', 'div'>>;
root: Slot<'div'>;
};

// @public
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import * as React from 'react';
import {
useControllableState,
useEventCallback,
useId,
useIsomorphicLayoutEffect,
useMergedRefs,
} from '@fluentui/react-utilities';
import { useControllableState, useEventCallback, useId, useIsomorphicLayoutEffect } from '@fluentui/react-utilities';
import { useHasParentContext } from '@fluentui/react-context-selector';
import { useControlNativeDialogOpenState, useDisableBodyScroll, useFocusFirstElement } from '../../utils';
import { useDisableBodyScroll, useFocusFirstElement } from '../../utils';
import { DialogContext } from '../../contexts';

import type { DialogOpenChangeData, DialogProps, DialogState } from './Dialog.types';
Expand Down Expand Up @@ -42,7 +36,6 @@ export const useDialog_unstable = (props: DialogProps): DialogState => {
});

const focusRef = useFocusFirstElement(open, modalType);
const nativeControlRef = useControlNativeDialogOpenState(open, modalType);
const disableBodyScroll = useDisableBodyScroll();
const isBodyScrollLocked = Boolean(open && modalType !== 'non-modal');

Expand All @@ -64,7 +57,7 @@ export const useDialog_unstable = (props: DialogProps): DialogState => {
dialogContentId: useId('dialog-content-'),
dialogTitleId: useId('dialog-title-'),
isNestedDialog: useHasParentContext(DialogContext),
dialogRef: useMergedRefs(focusRef, nativeControlRef),
dialogRef: focusRef,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export type DialogSurfaceSlots = {
* since native `<dialog>` element supports [::backdrop](https://developer.mozilla.org/en-US/docs/Web/CSS/::backdrop)
*/
backdrop?: Slot<'div'>;
root: NonNullable<Slot<'dialog', 'div'>>;
root: Slot<'div'>;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import type {
DialogSurfaceState,
} from './DialogSurface.types';
import { useDialogContext_unstable } from '../../contexts';
import { isEscapeKeyDismiss, HTMLDialogElementProps } from '../../utils';
import { isEscapeKeyDismiss } from '../../utils';
import { useModalAttributes } from '@fluentui/react-tabster';

/**
* Create the state required to render DialogSurface.
*
Expand All @@ -29,62 +30,13 @@ export const useDialogSurface_unstable = (
ref: React.Ref<DialogSurfaceElement>,
): DialogSurfaceState => {
const { backdrop, as } = props;
const isNativeDialog = as === 'dialog' || as === undefined;
const modalType = useDialogContext_unstable(ctx => ctx.modalType);
const dialogRef = useDialogContext_unstable(ctx => ctx.dialogRef);
const open = useDialogContext_unstable(ctx => ctx.open);
const requestOpenChange = useDialogContext_unstable(ctx => ctx.requestOpenChange);
const dialogTitleID = useDialogContext_unstable(ctx => ctx.dialogTitleId);
const dialogContentId = useDialogContext_unstable(ctx => ctx.dialogContentId);

const handleNativeClick = useEventCallback((event: React.MouseEvent<DialogSurfaceElementIntersection>) => {
props.onClick?.(event);
if (modalType === 'alert' || event.target !== event.currentTarget) {
return;
}
const { clientX, clientY } = event;
const { top, left, width, height } = event.currentTarget.getBoundingClientRect();
const isBackdropClick = top > clientY || clientY > top + height || left > clientX || clientX > left + width;
if (isBackdropClick) {
requestOpenChange({
event,
open: false,
type: 'backdropClick',
});
}
});

const handleNativeCancel = useEventCallback((event: React.SyntheticEvent<DialogSurfaceElementIntersection>) => {
(props as HTMLDialogElementProps).onCancel?.(event);
if (event.currentTarget !== event.target) {
return;
}
if (modalType !== 'alert') {
requestOpenChange({
event,
open: false,
type: 'dialogCancel',
});
}
event.preventDefault();
});

const handleNativeClose = useEventCallback((event: React.SyntheticEvent<DialogSurfaceElementIntersection>) => {
(props as HTMLDialogElementProps).onClose?.(event);
// Ensure dialog remains open if force closed by close event
if (event.currentTarget.open !== open) {
if (open) {
if (modalType === 'non-modal') {
event.currentTarget.show();
} else {
event.currentTarget.showModal();
}
} else {
event.currentTarget.close();
}
}
});

const handledBackdropClick = useEventCallback((event: React.MouseEvent<HTMLDivElement>) => {
if (isResolvedShorthand(props.backdrop)) {
props.backdrop.onClick?.(event);
Expand Down Expand Up @@ -118,27 +70,18 @@ export const useDialogSurface_unstable = (
return {
components: {
backdrop: 'div',
root: 'dialog',
root: 'div',
},
backdrop: resolveShorthand(backdrop, {
required: !isNativeDialog && open && modalType !== 'non-modal',
required: open && modalType !== 'non-modal',
defaultProps: {
'aria-hidden': 'true',
onClick: handledBackdropClick,
},
}),
root: getNativeElementProps(as ?? 'dialog', {
...(isNativeDialog
? {
role: modalType === 'alert' ? 'alertdialog' : undefined,
onClose: handleNativeClose,
onClick: handleNativeClick,
onCancel: handleNativeCancel,
}
: {
'aria-modal': modalType !== 'non-modal',
role: modalType === 'alert' ? 'alertdialog' : 'dialog',
}),
root: getNativeElementProps(as ?? 'div', {
'aria-modal': modalType !== 'non-modal',
role: modalType === 'alert' ? 'alertdialog' : 'dialog',
...props,
...modalAttributes,
onKeyDown: handleKeyDown,
Expand Down
2 changes: 0 additions & 2 deletions packages/react-components/react-dialog/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export * from './isEscapeKeyDown';
export * from './useDisableBodyScroll';
export * from './useFocusFirstElement';
export * from './isHTMLDialogElement';
export * from './useControlNativeDialogOpenState';
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as React from 'react';
import { Escape } from '@fluentui/keyboard-keys';
import type { DialogModalType } from '../components/Dialog/Dialog.types';
import { DialogSurfaceElement } from '../DialogSurface';
import { isHTMLDialogElement } from './isHTMLDialogElement';

/**
* Checks if keydown event is a proper Escape key dismiss
Expand All @@ -11,11 +10,5 @@ export function isEscapeKeyDismiss(
event: React.KeyboardEvent<DialogSurfaceElement>,
modalType: DialogModalType,
): boolean {
return (
event.key === Escape &&
// `non-modal` should always have Escape key handling
// `modal` should only be handled in the case of non native dialog
(modalType === 'non-modal' || (!isHTMLDialogElement(event.currentTarget) && modalType === 'modal')) &&
!event.isDefaultPrevented()
);
return event.key === Escape && modalType !== 'alert' && !event.isDefaultPrevented();
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useFocusFinders } from '@fluentui/react-tabster';
import { useFluent_unstable } from '@fluentui/react-shared-contexts';
import type { DialogSurfaceElement } from '../DialogSurface';
import type { DialogModalType } from '../Dialog';
import { isHTMLDialogElement } from './isHTMLDialogElement';

/**
* Focus first element on content when dialog is opened,
Expand All @@ -21,10 +20,7 @@ export function useFocusFirstElement(open: boolean, modalType: DialogModalType)
triggerRef.current = targetDocument?.activeElement as HTMLElement | undefined;
const element = dialogRef.current && findFirstFocusable(dialogRef.current);
if (element) {
// this is only required for non native dialogs
if (!isHTMLDialogElement(dialogRef.current)) {
element.focus();
}
element.focus();
} else if (process.env.NODE_ENV !== 'production') {
triggerRef.current?.blur();
// eslint-disable-next-line no-console
Expand Down