Skip to content

Instantly share code, notes, and snippets.

@lighth7015
Created February 23, 2024 02:09
Show Gist options
  • Save lighth7015/3acf50429bf80968e21f2998eaeeeb63 to your computer and use it in GitHub Desktop.
Save lighth7015/3acf50429bf80968e21f2998eaeeeb63 to your computer and use it in GitHub Desktop.
Dialog Provider
import React, { createContext, useContext, useState, FunctionComponent, useEffect } from 'react';
import { Dialog, Button } from '@mui/material';
type DialogProviderProps = React.PropsWithChildren;
type DialogContent = { component: FunctionComponent<any> | null; props: any; };
type ShowDialogFn = ( component: FunctionComponent<any>, props?: any ) => void;
type DialogCtx = { showDialog: ShowDialogFn; closeDialog: VoidFunction; open: boolean; content: DialogContent; };
const DialogContext = createContext<DialogCtx | undefined>( undefined );
function invariant ( condition: unknown, message: string ): asserts condition {
if ( !condition ) {
throw new Error( message );
}
}
const DialogProvider: React.FC<DialogProviderProps> = ( { children } ) => {
const [ isOpen, setIsOpen ] = useState( false );
const [ dialogContent, setDialogContent ] = useState<DialogContent>( { component: null, props: {} } );
const showDialog = ( component: FunctionComponent<any>, props?: any ) => {
setIsOpen( true );
setDialogContent( { component, props: props || {} } );
};
const closeDialog = () => {
setIsOpen( false );
setDialogContent( { component: null, props: {} } );
};
// Ensure the state is reset on unmount (cleanup for SSR)
useEffect( () => {
return () => {
setIsOpen( false );
setDialogContent( { component: null, props: {} } );
};
}, [] );
// Check if running on the client side
const isClient = typeof window !== 'undefined';
// Render the Dialog only on the client side
const renderDialog = isClient && isOpen && dialogContent.component && (
<Dialog open={ isOpen } onClose={ closeDialog }>
{ React.createElement( dialogContent.component, { ...dialogContent.props } ) }
<Button onClick={ closeDialog }>Close Dialog</Button>
</Dialog>
);
return (
<DialogContext.Provider value={ { showDialog, closeDialog, isOpen, dialogContent } }>
{ isClient && children }
{ renderDialog }
</DialogContext.Provider>
);
};
export default DialogProvider;
export const useDialog = (): DialogCtx => {
const context = useContext( DialogContext );
invariant( context, 'useDialog must be used within a DialogProvider' );
return context;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment