@spaced-out/ui-design-system
Version:
Sense UI components library
229 lines (205 loc) • 5.12 kB
Flow
// @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>
);