'use client'; import { Escape } from '@fluentui/keyboard-keys'; import { presenceMotionSlot } from '@fluentui/react-motion'; import { useEventCallback, useMergedRefs, isResolvedShorthand, slot, getIntrinsicElementProps, useIsomorphicLayoutEffect } from '@fluentui/react-utilities'; import * as React from 'react'; import { useDialogContext_unstable, useDialogBackdropContext_unstable } from '../../contexts'; import { useDisableBodyScroll } from '../../utils/useDisableBodyScroll'; import { DialogBackdropMotion } from '../DialogBackdropMotion'; import { useMotionForwardedRef } from '@fluentui/react-motion'; /** * Create the state required to render DialogSurface. * * The returned state can be modified with hooks such as useDialogSurfaceStyles_unstable, * before being passed to renderDialogSurface_unstable. * * @param props - props from this instance of DialogSurface * @param ref - reference to root HTMLElement of DialogSurface */ export const useDialogSurface_unstable = (props, ref)=>{ const contextRef = useMotionForwardedRef(); const modalType = useDialogContext_unstable((ctx)=>ctx.modalType); const isNestedDialog = useDialogContext_unstable((ctx)=>ctx.isNestedDialog); const backdropOverride = useDialogBackdropContext_unstable(); const treatBackdropAsNested = backdropOverride !== null && backdropOverride !== void 0 ? backdropOverride : isNestedDialog; const modalAttributes = useDialogContext_unstable((ctx)=>ctx.modalAttributes); const dialogRef = useDialogContext_unstable((ctx)=>ctx.dialogRef); const requestOpenChange = useDialogContext_unstable((ctx)=>ctx.requestOpenChange); const dialogTitleID = useDialogContext_unstable((ctx)=>ctx.dialogTitleId); const open = useDialogContext_unstable((ctx)=>ctx.open); const unmountOnClose = useDialogContext_unstable((ctx)=>ctx.unmountOnClose); const handledBackdropClick = useEventCallback((event)=>{ if (isResolvedShorthand(props.backdrop)) { var _props_backdrop_onClick, _props_backdrop; (_props_backdrop_onClick = (_props_backdrop = props.backdrop).onClick) === null || _props_backdrop_onClick === void 0 ? void 0 : _props_backdrop_onClick.call(_props_backdrop, event); } if (modalType === 'modal' && !event.isDefaultPrevented()) { requestOpenChange({ event, open: false, type: 'backdropClick' }); } }); const handleKeyDown = useEventCallback((event)=>{ var _props_onKeyDown; (_props_onKeyDown = props.onKeyDown) === null || _props_onKeyDown === void 0 ? void 0 : _props_onKeyDown.call(props, event); if (event.key === Escape && !event.isDefaultPrevented()) { requestOpenChange({ event, open: false, type: 'escapeKeyDown' }); // stop propagation to avoid conflicting with other elements that listen for `Escape` // e,g: nested Dialog, Popover, Menu and Tooltip event.preventDefault(); } }); const backdrop = slot.optional(props.backdrop, { renderByDefault: modalType !== 'non-modal', defaultProps: { 'aria-hidden': 'true' }, elementType: 'div' }); const backdropAppearance = backdrop === null || backdrop === void 0 ? void 0 : backdrop.appearance; if (backdrop) { backdrop.onClick = handledBackdropClick; // remove backdrop.appearance so it is not passed to the DOM delete backdrop.appearance; } const { disableBodyScroll, enableBodyScroll } = useDisableBodyScroll(); useIsomorphicLayoutEffect(()=>{ if (!open) { enableBodyScroll(); return; } if (isNestedDialog || modalType === 'non-modal') { return; } disableBodyScroll(); return ()=>enableBodyScroll(); }, [ open, modalType, isNestedDialog, disableBodyScroll, enableBodyScroll ]); return { components: { backdrop: 'div', root: 'div', backdropMotion: DialogBackdropMotion }, open, backdrop, isNestedDialog, treatBackdropAsNested, backdropAppearance, unmountOnClose, mountNode: props.mountNode, root: slot.always(getIntrinsicElementProps('div', { tabIndex: -1, role: modalType === 'alert' ? 'alertdialog' : 'dialog', 'aria-modal': modalType !== 'non-modal', 'aria-labelledby': props['aria-label'] ? undefined : dialogTitleID, 'aria-hidden': !unmountOnClose && !open ? true : undefined, ...props, ...modalAttributes, onKeyDown: handleKeyDown, // FIXME: // `DialogSurfaceElement` is wrongly assigned to be `HTMLElement` instead of `HTMLDivElement` // but since it would be a breaking change to fix it, we are casting ref to it's proper type ref: useMergedRefs(ref, contextRef, dialogRef) }), { elementType: 'div' }), backdropMotion: presenceMotionSlot(props.backdropMotion, { elementType: DialogBackdropMotion, defaultProps: { appear: unmountOnClose, visible: open } }), // Deprecated properties transitionStatus: undefined }; };