diff --git a/change/@fluentui-react-dialog-f0db0d7e-2454-43bc-91e3-d5eed405519c.json b/change/@fluentui-react-dialog-f0db0d7e-2454-43bc-91e3-d5eed405519c.json new file mode 100644 index 00000000000000..5c3822621ea60f --- /dev/null +++ b/change/@fluentui-react-dialog-f0db0d7e-2454-43bc-91e3-d5eed405519c.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "feat: removes DialogSurface native dialog support ", + "packageName": "@fluentui/react-dialog", + "email": "bernardo.sunderhus@gmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-dialog/etc/react-dialog.api.md b/packages/react-components/react-dialog/etc/react-dialog.api.md index 23305f289c0e59..39d3c6cc52e984 100644 --- a/packages/react-components/react-dialog/etc/react-dialog.api.md +++ b/packages/react-components/react-dialog/etc/react-dialog.api.md @@ -137,7 +137,7 @@ export type DialogSurfaceProps = Omit, 'open' // @public (undocumented) export type DialogSurfaceSlots = { backdrop?: Slot<'div'>; - root: NonNullable>; + root: Slot<'div'>; }; // @public diff --git a/packages/react-components/react-dialog/src/components/Dialog/useDialog.ts b/packages/react-components/react-dialog/src/components/Dialog/useDialog.ts index 763ddf618ddd42..8a96386c788a25 100644 --- a/packages/react-components/react-dialog/src/components/Dialog/useDialog.ts +++ b/packages/react-components/react-dialog/src/components/Dialog/useDialog.ts @@ -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'; @@ -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'); @@ -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, }; }; diff --git a/packages/react-components/react-dialog/src/components/DialogSurface/DialogSurface.types.ts b/packages/react-components/react-dialog/src/components/DialogSurface/DialogSurface.types.ts index 2ebd2543c8e0f4..32e4ef164e8d92 100644 --- a/packages/react-components/react-dialog/src/components/DialogSurface/DialogSurface.types.ts +++ b/packages/react-components/react-dialog/src/components/DialogSurface/DialogSurface.types.ts @@ -12,7 +12,7 @@ export type DialogSurfaceSlots = { * since native `` element supports [::backdrop](https://developer.mozilla.org/en-US/docs/Web/CSS/::backdrop) */ backdrop?: Slot<'div'>; - root: NonNullable>; + root: Slot<'div'>; }; /** diff --git a/packages/react-components/react-dialog/src/components/DialogSurface/useDialogSurface.ts b/packages/react-components/react-dialog/src/components/DialogSurface/useDialogSurface.ts index 02915c7b50388d..a3e72e019ca73e 100644 --- a/packages/react-components/react-dialog/src/components/DialogSurface/useDialogSurface.ts +++ b/packages/react-components/react-dialog/src/components/DialogSurface/useDialogSurface.ts @@ -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. * @@ -29,7 +30,6 @@ export const useDialogSurface_unstable = ( ref: React.Ref, ): 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); @@ -37,54 +37,6 @@ export const useDialogSurface_unstable = ( const dialogTitleID = useDialogContext_unstable(ctx => ctx.dialogTitleId); const dialogContentId = useDialogContext_unstable(ctx => ctx.dialogContentId); - const handleNativeClick = useEventCallback((event: React.MouseEvent) => { - 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) => { - (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) => { - (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) => { if (isResolvedShorthand(props.backdrop)) { props.backdrop.onClick?.(event); @@ -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, diff --git a/packages/react-components/react-dialog/src/utils/index.ts b/packages/react-components/react-dialog/src/utils/index.ts index d713825c749b09..ed3d5165c8c5a9 100644 --- a/packages/react-components/react-dialog/src/utils/index.ts +++ b/packages/react-components/react-dialog/src/utils/index.ts @@ -1,5 +1,3 @@ export * from './isEscapeKeyDown'; export * from './useDisableBodyScroll'; export * from './useFocusFirstElement'; -export * from './isHTMLDialogElement'; -export * from './useControlNativeDialogOpenState'; diff --git a/packages/react-components/react-dialog/src/utils/isEscapeKeyDown.ts b/packages/react-components/react-dialog/src/utils/isEscapeKeyDown.ts index 66dc354389f70c..6acb06762e5e0e 100644 --- a/packages/react-components/react-dialog/src/utils/isEscapeKeyDown.ts +++ b/packages/react-components/react-dialog/src/utils/isEscapeKeyDown.ts @@ -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 @@ -11,11 +10,5 @@ export function isEscapeKeyDismiss( event: React.KeyboardEvent, 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(); } diff --git a/packages/react-components/react-dialog/src/utils/isHTMLDialogElement.ts b/packages/react-components/react-dialog/src/utils/isHTMLDialogElement.ts deleted file mode 100644 index 537a09b44963e3..00000000000000 --- a/packages/react-components/react-dialog/src/utils/isHTMLDialogElement.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as React from 'react'; - -export function isHTMLDialogElement(element?: HTMLElement | null): element is HTMLDialogElement { - return Boolean(element && 'open' in element && 'show' in element && 'showModal' in element && 'close' in element); -} - -/** - * adds additional types which are missing from current version of react - * @internal - */ -export type HTMLDialogElementProps = JSX.IntrinsicElements['dialog'] & { - /** - * The close event is fired on a when it has been closed. - */ - onClose?: (event: React.SyntheticEvent) => void; - /** - * The cancel event fires on a when - * the user instructs the browser that they wish to dismiss the current open dialog. - * For example, the browser might fire this event when the user presses the Esc - * key. - */ - onCancel?: (event: React.SyntheticEvent) => void; -}; diff --git a/packages/react-components/react-dialog/src/utils/useControlNativeDialogOpenState.ts b/packages/react-components/react-dialog/src/utils/useControlNativeDialogOpenState.ts deleted file mode 100644 index a49fa6b938ae09..00000000000000 --- a/packages/react-components/react-dialog/src/utils/useControlNativeDialogOpenState.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as React from 'react'; -import { isHTMLDialogElement } from './isHTMLDialogElement'; -import type { DialogModalType } from '../Dialog'; -import type { DialogSurfaceElement } from '../DialogSurface'; - -export function useControlNativeDialogOpenState(open: boolean, modalType: DialogModalType) { - const dialogSurfaceRef = React.useRef(null); - - React.useEffect(() => { - if (isHTMLDialogElement(dialogSurfaceRef.current) && dialogSurfaceRef.current.open !== open) { - if (open) { - if (modalType === 'non-modal') { - dialogSurfaceRef.current.show(); - } else { - dialogSurfaceRef.current.showModal(); - } - } else { - dialogSurfaceRef.current.close(); - } - } - }, [open, modalType]); - - return dialogSurfaceRef; -} diff --git a/packages/react-components/react-dialog/src/utils/useFocusFirstElement.ts b/packages/react-components/react-dialog/src/utils/useFocusFirstElement.ts index 4bab59d08f110c..bd565daefde7c1 100644 --- a/packages/react-components/react-dialog/src/utils/useFocusFirstElement.ts +++ b/packages/react-components/react-dialog/src/utils/useFocusFirstElement.ts @@ -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, @@ -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