github.com/grafana/pyroscope@v1.18.0/public/app/ui/Dialog/Dialog.tsx (about) 1 /* eslint-disable react/jsx-props-no-spreading */ 2 import React, { Ref, ReactNode } from 'react'; 3 import ModalUnstyled from '@mui/base/ModalUnstyled'; 4 import Button from '@pyroscope/ui/Button'; 5 import cx from 'classnames'; 6 import styles from './Dialog.module.css'; 7 8 const Backdrop = React.forwardRef< 9 HTMLDivElement, 10 { open?: boolean; className: string } 11 >((props, ref) => { 12 const { className, ...other } = props; 13 return ( 14 <div className={`${className} ${styles.backdrop}`} ref={ref} {...other} /> 15 ); 16 }); 17 18 Backdrop.displayName = 'Backdrop'; 19 20 type DialogHeaderProps = { children: ReactNode; className?: string } & ( 21 | { closeable: true; onClose: () => void } 22 | { closeable?: false } 23 ); 24 export const DialogHeader = React.forwardRef( 25 (props: DialogHeaderProps, ref?: Ref<HTMLInputElement>) => { 26 const { children, className, closeable } = props; 27 return ( 28 <div className={cx(styles.header, className)} ref={ref}> 29 {children} 30 {closeable ? ( 31 <Button 32 aria-label="Close" 33 onClick={() => props.onClose()} 34 noBox 35 className={styles.closeButton} 36 /> 37 ) : null} 38 </div> 39 ); 40 } 41 ); 42 DialogHeader.displayName = 'DialogHeader'; 43 44 interface DialogFooterProps { 45 children: ReactNode; 46 className?: string; 47 } 48 export const DialogFooter = React.forwardRef( 49 (props: DialogFooterProps, ref?: Ref<HTMLInputElement>) => { 50 const { children, className } = props; 51 return ( 52 <div className={cx(styles.footer, className)} ref={ref}> 53 {children} 54 </div> 55 ); 56 } 57 ); 58 DialogFooter.displayName = 'DialogFooter'; 59 60 interface DialogBodyProps { 61 children: ReactNode; 62 className?: string; 63 } 64 export const DialogBody = React.forwardRef( 65 (props: DialogBodyProps, ref?: Ref<HTMLInputElement>) => { 66 const { children, className } = props; 67 return ( 68 <div className={cx(styles.body, className)} ref={ref}> 69 {children} 70 </div> 71 ); 72 } 73 ); 74 DialogBody.displayName = 'DialogBody'; 75 76 type DialogProps = Exclude< 77 React.ComponentProps<typeof ModalUnstyled>, 78 'components' 79 > & { 80 className?: string; 81 /** The header ID */ 82 ['aria-labelledby']: string; 83 }; 84 export function Dialog(props: DialogProps) { 85 const { className } = props; 86 return ( 87 <ModalUnstyled 88 {...props} 89 components={{ Backdrop }} 90 className={cx(styles.modal, className)} 91 > 92 <div 93 aria-modal="true" 94 aria-labelledby={props['aria-labelledby']} 95 className={styles.modalContainer} 96 > 97 {props.children} 98 </div> 99 </ModalUnstyled> 100 ); 101 } 102 103 export function DialogActions({ children }: { children: React.ReactNode }) { 104 return <div className={styles.dialogActions}>{children}</div>; 105 }