import m from 'mithril'; import classnames from 'classnames'; import { AbstractComponent } from '../abstract-component'; import { IAttrs, Classes, safeCall, getClosest } from '../../_shared'; import { Overlay, IOverlayableAttrs } from '../overlay'; import { Button } from '../button'; import { Icons } from '../icon'; export interface IDialogAttrs extends IOverlayableAttrs, IAttrs { /** Toggles basic styling (no header/footer border and background) */ basic?: boolean; /** * Wether closed button is present in header * @default true */ hasCloseButton?: boolean; /** Toggles visibility */ isOpen?: boolean; /** Title of dialog */ title?: string; /** Inner content */ content?: m.Children; /** Footer content */ footer?: m.Children; } export class Dialog extends AbstractComponent { public getDefaultAttrs() { return { hasCloseButton: true, closeOnOutsideClick: true }; } public view() { const { basic, onClose, hasCloseButton, class: className, footer, content, style, title, ...otherAttrs } = this.attrs; const closeButton = m(Button, { class: Classes.DIALOG_CLOSE_BUTTON, basic: true, iconLeft: Icons.X, onclick: onClose ? (e: Event) => onClose(e) : undefined }); const header = m('', { class: Classes.DIALOG_HEADER }, [ m('h3', title), hasCloseButton && closeButton ]); const innerContent = m('', { class: Classes.DIALOG_CONTENT }, [ title && header, m('', { class: Classes.DIALOG_BODY }, content), footer && m('', { class: Classes.DIALOG_FOOTER }, footer) ]); const container = m('', { class: classnames( Classes.DIALOG, basic && Classes.BASIC, className ), onclick: this.handleContainerClick, style }, innerContent); return m(Overlay, { ...otherAttrs, onClose, content: container }); } private handleContainerClick = (e: Event) => { const { closeOnOutsideClick, onClose } = this.attrs; const target = e.target as HTMLElement; const isClickOutsideDialog = getClosest(target, `.${Classes.DIALOG_CONTENT}`) == null; if (isClickOutsideDialog && closeOnOutsideClick) { safeCall(onClose); } else (e as any).redraw = false; }; }