UNPKG

@spaced-out/ui-design-system

Version:
229 lines (205 loc) 5.12 kB
// @flow strict import * as React from 'react'; import {TEXT_COLORS} from '../../types/typography'; import classify from '../../utils/classify'; import {Button} from '../Button'; import {Icon} from '../Icon'; import type {ModalProps} from '../Modal'; import {Modal} from '../Modal'; import css from './Dialog.module.css'; type FooterClassNames = $ReadOnly<{ wrapper?: string, actions?: string, }>; export const DIALOG_SEMANTIC = Object.freeze({ neutral: 'neutral', success: 'success', information: 'information', warning: 'warning', danger: 'danger', }); export type DialogSemanticType = $Values<typeof DIALOG_SEMANTIC>; export type DialogHeaderProps = { children?: React.Node, className?: string, }; export type DialogFooterProps = { children?: React.Node, classNames?: FooterClassNames, }; export type DialogBodyProps = { children?: React.Node, className?: string, }; export type DialogPropsBase = { ...ModalProps, }; export type DialogProps = { ...DialogPropsBase, semantic?: DialogSemanticType, iconName?: string, }; export type BasicDialogProps = { ...DialogProps, heading?: React.Node, body?: React.Node, confirmText?: string, abortText?: string, handleConfirm?: (event: SyntheticEvent<>) => mixed, handleAbort?: (event: SyntheticEvent<>) => mixed, }; const DialogIcon = ({ semantic, iconName, }: { semantic: DialogSemanticType, iconName: string, }) => { switch (semantic) { case DIALOG_SEMANTIC.neutral: return ( <Icon color={TEXT_COLORS.neutral} name={iconName ? iconName : 'face-smile'} type="solid" /> ); case DIALOG_SEMANTIC.success: return ( <Icon name={iconName ? iconName : 'circle-check'} color={TEXT_COLORS.success} type="solid" /> ); case DIALOG_SEMANTIC.information: return ( <Icon name={iconName ? iconName : 'circle-info'} color={TEXT_COLORS.information} type="solid" /> ); case DIALOG_SEMANTIC.warning: return ( <Icon name={iconName ? iconName : 'circle-exclamation'} color={TEXT_COLORS.warning} type="solid" /> ); case DIALOG_SEMANTIC.danger: return ( <Icon name={iconName ? iconName : 'shield-exclamation'} color={TEXT_COLORS.danger} type="solid" /> ); default: return ( <Icon color={TEXT_COLORS.neutral} name={iconName ? iconName : 'face-smile'} type="solid" /> ); } }; export const DialogHeader = ({ children, className, }: DialogHeaderProps): React.Node => ( <> {React.Children.count(children) > 0 && ( <div className={classify(css.dialogHeader, className)}> <div className={css.headerContent}>{children}</div> </div> )} </> ); export const DialogBody = ({ children, className, }: DialogBodyProps): React.Node => ( <div className={classify(css.dialogBody, className)}>{children}</div> ); export const DialogFooter = ({ children, classNames, }: DialogFooterProps): React.Node => ( <> {React.Children.count(children) > 0 && ( <div className={classify(css.dialogFooter, classNames?.wrapper)}> <div className={classify(css.dialogFooterActions, classNames?.actions)}> {children} </div> </div> )} </> ); export const Dialog = ({ children, isOpen = false, hideBackdrop = false, onClose, tapOutsideToClose = false, iconName = '', semantic = 'neutral', classNames, ...restDialogProps }: DialogProps): React.Node => ( <Modal isOpen={isOpen} onClose={onClose} hideBackdrop={hideBackdrop} tapOutsideToClose={tapOutsideToClose} {...restDialogProps} classNames={{ content: classify(css.dialog, classNames?.content), container: classify(classNames?.container), backdrop: classify(classNames?.backdrop), }} > <div className={css.topBlock}> <div className={classify(css.iconContainer, { [css.neutral]: semantic === DIALOG_SEMANTIC.neutral, [css.success]: semantic === DIALOG_SEMANTIC.success, [css.information]: semantic === DIALOG_SEMANTIC.information, [css.warning]: semantic === DIALOG_SEMANTIC.warning, [css.danger]: semantic === DIALOG_SEMANTIC.danger, })} > <DialogIcon semantic={semantic} iconName={iconName} /> </div> </div> {children} </Modal> ); export const BasicDialog = ({ heading, body, confirmText, abortText, handleConfirm, handleAbort, ...restDialogProps }: BasicDialogProps): React.Node => ( <Dialog {...restDialogProps}> {!!heading && <DialogHeader>{heading}</DialogHeader>} {!!body && <DialogBody>{body}</DialogBody>} <DialogFooter> {!!abortText && ( <Button isFluid type="tertiary" onClick={handleAbort}> {abortText} </Button> )} {!!confirmText && ( <Button isFluid onClick={handleConfirm}> {confirmText} </Button> )} </DialogFooter> </Dialog> );