William O'Beirne aa0f9cd455 Electron Redesign (#1505)
* Frameless Electron. Separate electron template. Generecize navigation link. Move nav info to config.

* Add controls for language and node, network status to sidebar.

* Sticky headers

* Move custom node modal into standalone component. Render modals via portal. Add custom node modal opening to electron node list.

* Conditional styling based on environment.

* Fix active node highlight

* Add frame back in, draggable only on OSX, fix sidebar scroll.

* Remove panel content after delay.

* Adjust window sizes

* Style desktop help nav icon

* Remove unused var

* Move style to param

* Remove unused

* Update snapshot

* Fix oversized stretching, zindex fighting

* Make electron work better with various screen sizes

* Remove not-working https option for electron

* Add beta banner

* Fix web footer

* Address changes
2018-04-16 18:30:58 -05:00

90 lines
2.5 KiB
TypeScript

import React, { PureComponent } from 'react';
import { createPortal } from 'react-dom';
import ModalBody from './ModalBody';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import './index.scss';
export interface IButton {
text: string | React.ReactElement<string>;
type?: 'default' | 'primary' | 'success' | 'info' | 'warning' | 'danger' | 'link';
disabled?: boolean;
onClick?(): void;
}
interface Props {
isOpen?: boolean;
title?: string;
disableButtons?: boolean;
children: any;
buttons?: IButton[];
maxWidth?: number;
handleClose(): void;
}
interface ModalStyle {
width?: string;
maxWidth?: string;
}
const Fade = ({ ...props }: any) => (
<CSSTransition {...props} timeout={300} classNames="animate-modal" />
);
export default class Modal extends PureComponent<Props, {}> {
public modalParent: HTMLElement;
public modalBody: ModalBody;
public componentDidUpdate(prevProps: Props) {
if (prevProps.isOpen !== this.props.isOpen) {
document.body.classList.toggle('no-scroll', !!this.props.isOpen);
}
}
public componentDidMount() {
const modalEl = document.getElementById('ModalContainer');
if (modalEl) {
this.modalParent = document.createElement('div');
modalEl.appendChild(this.modalParent);
}
}
public componentWillUnmount() {
document.body.classList.remove('no-scroll');
const modalEl = document.getElementById('ModalContainer');
if (modalEl) {
modalEl.removeChild(this.modalParent);
}
}
public render() {
const { isOpen, title, children, buttons, handleClose, maxWidth } = this.props;
const hasButtons = buttons && buttons.length;
const modalStyle: ModalStyle = {};
if (maxWidth) {
modalStyle.width = '100%';
modalStyle.maxWidth = `${maxWidth}px`;
}
const modalBodyProps = { title, children, modalStyle, hasButtons, buttons, handleClose };
const modal = (
<TransitionGroup>
{isOpen && (
// Trap focus in modal by focusing the first element after the animation is complete
<Fade onEntered={() => this.modalBody.firstTabStop.focus()}>
<div>
<div className="Modal-overlay" onClick={handleClose} />
<ModalBody {...modalBodyProps} ref={div => (this.modalBody = div as ModalBody)} />
</div>
</Fade>
)}
</TransitionGroup>
);
if (this.modalParent) {
return createPortal(modal, this.modalParent);
} else {
return modal;
}
}
}