import ReactDOM from 'react-dom'; import { createElemPropsHook, createSubcomponent, useForkRef, useWindowSize, } from '@workday/canvas-kit-react/common'; import {Box, BoxProps, mergeStyles} from '@workday/canvas-kit-react/layout'; import {usePopupModel, usePopupStack} from '@workday/canvas-kit-react/popup'; import {createStencil, keyframes} from '@workday/canvas-kit-styling'; import {system} from '@workday/canvas-tokens-web'; import {useModalModel} from './hooks'; export interface ModalOverlayProps extends BoxProps {} const fadeIn = keyframes({ '0%': { background: 'none', }, '100%': { background: system.legacy.color.surface.overlay.scrim, }, }); export const modalOverlayContainerStencil = createStencil({ vars: { containerCenter: '', }, base: ({containerCenter}) => ({ position: 'fixed', top: 0, left: 0, width: '100vw', height: '100vh', background: system.legacy.color.surface.overlay.scrim, animationDuration: '0.3s', animationName: fadeIn, // Allow overriding of animation in special cases '.wd-no-animation &': { animation: 'none', }, // Responsive Container '& > div': { maxHeight: '100%', display: 'flex', position: 'absolute', left: 0, top: 0, justifyContent: 'center', alignItems: 'center', height: '100%', width: containerCenter, }, '@media screen and (max-width: 768px)': { height: '100%', '& > div': { alignItems: 'end', }, }, }), }); export const useModalOverlay = createElemPropsHook(usePopupModel)(({state}, ref) => { const elementRef = useForkRef(ref, state.stackRef); usePopupStack(elementRef, state.targetRef); return { // The ref should not be applied to an element. The passed ref will apply to the stackRef instead ref: undefined, }; }); const OpenModalOverlay = createSubcomponent('div')({ displayName: 'Modal.OpenOverlay', modelHook: useModalModel, elemPropsHook: useModalOverlay, })((elemProps, Element, model) => { const windowSize = useWindowSize(); const containerCenter = windowSize.width % 2 === 1 ? 'calc(100vw - 1px)' : '100vw'; const content = ( {/* This centering container helps fix an issue with Chrome. Chrome doesn't normally do subpixel positioning, but seems to when using flexbox centering. This messes up Popper calculations inside the Modal. The centering container forces a "center" pixel calculation by making sure the width is always an even number */} {elemProps.children} ); // only render something on the client if (typeof window !== 'undefined') { return ReactDOM.createPortal(content, model!.state.stackRef.current!); } else { return null; } }); export const ModalOverlay = createSubcomponent('div')({ displayName: 'Modal.Overlay', modelHook: useModalModel, })((elemProps, Element, model) => { return model.state.visibility !== 'hidden' ? ( ) : null; });