UNPKG

stem-core

Version:

Frontend and core-library framework

215 lines (179 loc) 6.22 kB
import {ButtonGroup} from "../button/ButtonGroup"; import {Button} from "../button/Button"; import {FloatingWindow} from "./FloatingWindow"; import {ModalStyle} from "./Style"; import {Panel, TemporaryMessageArea} from "../UIPrimitives"; import {UI} from "../UIBase"; import {Dispatcher} from "../../base/Dispatcher"; import {registerStyle} from "../style/Theme"; import {Level, Size} from "../Constants"; @registerStyle(ModalStyle) class Modal extends UI.Element { getDefaultOptions() { return { closeButton: true, destroyOnHide: true, visible: false, }; } getChildrenToRender() { return [ <Panel ref="modalContainer" className={(this.options.visible ? "" : "hidden") + this.styleSheet.container}> <Panel ref="behindPanel" className={this.styleSheet.hiddenAnimated + this.styleSheet.background} onClick={() => this.hide()}/> {this.getModalWindow()} </Panel> ]; } getModalWindow() { let closeButton = null; if (this.options.closeButton) { // TODO: this should be in a method closeButton = <div style={{right: "10px", zIndex: "10", position: "absolute"}}> <Button className="close" size={Size.EXTRA_LARGE} style={{border: "none"}} label="&times;" onClick={() => this.hide()}/> </div>; } return <FloatingWindow ref="modalWindow" style={this.getModalWindowStyle()}> {closeButton} {this.render()} </FloatingWindow>; } getModalWindowStyle() { if (this.options.fillScreen) { this.options.width = "85%"; } // TODO(@Rocky): I don't like this very much, honestly... return { position: "relative", padding: "1%", boxShadow: "0 5px 15px rgba(0,0,0,0.5)", borderRadius: "10px", margin: "60px auto", display: this.options.display || "block", maxHeight: this.options.maxHeight || "85%", left: "0", right: "0", width: this.options.width || "50%", height: this.options.height || "auto", background: "white", overflow: this.options.overflow || "auto", }; } isVisible() { return this.options.visible; } hide() { if (!this.isVisible()) { return; } this.options.visible = false; this.modalWindow.fadeOut(); setTimeout(() => { this.behindPanel.removeClass(this.styleSheet.visibleAnimated); this.behindPanel.addClass(this.styleSheet.hiddenAnimated); setTimeout(() => { this.modalContainer.addClass("hidden"); if (this.options.destroyOnHide) { this.destroyNode(); } }, this.modalWindow.options.transitionTime || 0); this.detachListener(this.closeListenerHandler); }, this.modalWindow.options.transitionTime || 0); document.body.classList.remove("unscrollable"); } show() { this.options.visible = true; if (!this.node) { this.mount(document.body); } this.modalContainer.removeClass("hidden"); setTimeout(() => { this.behindPanel.addClass(this.styleSheet.visibleAnimated); this.behindPanel.removeClass(this.styleSheet.hiddenAnimated); setTimeout(() => { this.modalWindow.fadeIn(); }, this.modalWindow.options.transitionTime); }, 0); this.closeListenerHandler = this.attachListener(Dispatcher.Global, "closeAllModals", () => { this.hide(); }); document.body.classList.add("unscrollable"); } static show(options={}) { let modal = new this(options); modal.show(); return modal; } } class ActionModal extends Modal { getDefaultOptions() { return Object.assign(super.getDefaultOptions(), { closeButton: false }); } getActionName() { return this.options.actionName; } getActionLevel() { return this.options.level || Level.DEFAULT; } getCloseName() { return this.options.closeName || "Close"; } render() { return [ <div className={this.styleSheet.header}>{this.getHeader()}</div>, (this.getBody() ? <div className={this.styleSheet.body}>{this.getBody()}</div> : null), (this.getFooter() ? <div className={this.styleSheet.footer}>{this.getFooter()}</div> : null) ]; } getHeader() { return <h4>{this.getTitle()}</h4>; } getTitle() { return this.options.title || this.getActionName(); } getBody() { return null; } getActionButton() { return <Button level={this.getActionLevel()} label={this.getActionName()} onClick={() => this.action()} ref="actionButton" />; } getFooter() { return [ <TemporaryMessageArea ref="messageArea"/>, <ButtonGroup> <Button label={this.getCloseName()} onClick={() => this.hide()}/> {this.getActionButton()} </ButtonGroup> ]; } action() {} } const ActionModalButton = (ActionModal) => class ActionModalButton extends Button { getModalOptions() { let modalOptions = { actionName: this.options.label, level: this.options.level }; Object.assign(modalOptions, this.options.modalOptions); return modalOptions; } onMount() { this.addClickListener(() => { ActionModal.show(this.getModalOptions()); }); } }; class ErrorModal extends ActionModal { getTitle() { return "An Error occurred"; } getBody() { return this.options.error.message || this.options.error; } getFooter() { return <Button level={Level.DANGER} label="Dismiss" onClick={() => this.hide()}/>; } } export {Modal, ErrorModal, ActionModal, ActionModalButton};