import React from 'react'; import { Dialog, DialogContext } from '../components/dialog'; import { EmptyState } from '../components/empty-state'; import { ExclamationCircle } from '../icons/glyphs/exclamation-circle'; import { useMessages } from '../localization'; import { useActor } from '../machine/use-machine'; import type { PortalContainer } from '../primitives/portal'; import { PortalProvider } from '../primitives/portal'; import type { ModalHandle, ModalSurface, ModalSurfaces } from './modal.types'; export function ModalHost({ surfaces, children, }: { surfaces: ModalSurfaces; children: React.ReactNode; }): React.ReactElement { return ( <> {surfaces.reduceRight( (inner, { id, Host }) => ( {inner} ), children, )} ); } export function ModalSurfaceHost({ surface, children, }: { surface: ModalSurface; children: React.ReactNode; }): React.ReactElement { const [state, setState] = React.useState>({ open: false, options: undefined, container: undefined, openCount: 0, }); const modal = React.useMemo>(() => { const preload = () => surface.loader.send({ type: 'LOAD' }); return { open: (options, container) => { preload(); setState(previous => ({ open: true, options, container, openCount: previous.openCount + 1 })); }, close: () => setState(previous => (previous.open ? { ...previous, open: false } : previous)), preload, isOpen: state.open, }; }, [surface, state.open]); return ( {children} ); } function ModalSlot({ surface, state, close, }: { surface: ModalSurface; state: ModalState; close: () => void; }) { const [content] = useActor(surface.loader); const { Content } = content.context; const failed = content.value === 'failed'; const dialog = ( { if (!open) { close(); } }} > {Content ? ( ) : failed ? ( ) : null} ); return state.container === undefined ? dialog : {dialog}; } function LoadFailed() { const m = useMessages('errors'); const dialog = React.useContext(DialogContext); return ( {m.generic} ); } interface ModalState { open: boolean; options: Options | undefined; container: PortalContainer | undefined; openCount: number; }