import AKButton from '@atlaskit/button'; import AKButtonGroup from '@atlaskit/button-group'; import ModalDialog from '@atlaskit/modal-dialog'; import { AtlasKitThemeProvider } from '@atlaskit/theme'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { translate } from '../../i18n'; import { DIALOG_PROP_TYPES } from '../constants'; /** * The ID to be used for the cancel button if enabled. * @type {string} */ const CANCEL_BUTTON_ID = 'modal-dialog-cancel-button'; /** * The ID to be used for the ok button if enabled. * @type {string} */ const OK_BUTTON_ID = 'modal-dialog-ok-button'; /** * Web dialog that uses atlaskit modal-dialog to display dialogs. */ class StatelessDialog extends Component { /** * {@code StatelessDialog} component's property types. * * @static */ static propTypes = { ...DIALOG_PROP_TYPES, /** * This is the body of the dialog, the component children. */ children: PropTypes.node, /** * Disables dismissing the dialog when the blanket is clicked. Enabled * by default. */ disableBlanketClickDismiss: PropTypes.bool, /** * Whether the dialog is modal. This means clicking on the blanket will * leave the dialog open. No cancel button. */ isModal: PropTypes.bool, /** * Disables rendering of the submit button. */ submitDisabled: PropTypes.bool, /** * Width of the dialog, can be: * - 'small' (400px), 'medium' (600px), 'large' (800px), * 'x-large' (968px) * - integer value for pixel width * - string value for percentage */ width: PropTypes.string }; /** * Initializes a new {@code StatelessDialog} instance. * * @param {Object} props - The read-only properties with which the new * instance is to be initialized. */ constructor(props) { super(props); // Bind event handlers so they are only bound once for every instance. this._onCancel = this._onCancel.bind(this); this._onDialogDismissed = this._onDialogDismissed.bind(this); this._onKeyDown = this._onKeyDown.bind(this); this._onSubmit = this._onSubmit.bind(this); this._setDialogElement = this._setDialogElement.bind(this); } /** * React Component method that executes once component is mounted. * * @inheritdoc */ componentDidMount() { this._updateButtonFocus(); } /** * React Component method that executes once component is updated. * * @param {Object} prevProps - The previous properties, before the update. * @returns {void} */ componentDidUpdate(prevProps) { // if there is an update in any of the buttons enable/disable props // update the focus if needed if (prevProps.okDisabled !== this.props.okDisabled || prevProps.cancelDisabled !== this.props.cancelDisabled || prevProps.submitDisabled !== this.props.submitDisabled) { this._updateButtonFocus(); } } /** * Implements React's {@link Component#render()}. * * @inheritdoc * @returns {ReactElement} */ render() { return ( /** * Enabled light theme for dialogs until all in-dialog components * support dark theme. */
); } /** * Dispatches action to hide the dialog. * * @returns {void} */ _onCancel() { if (!this.props.isModal) { this.props.onCancel(); } } /** * Handles click on the blanket area. * * @returns {void} */ _onDialogDismissed() { if (!this.props.disableBlanketClickDismiss) { this._onCancel(); } } /** * Dispatches the action when submitting the dialog. * * @private * @param {string} value - The submitted value if any. * @returns {void} */ _onSubmit(value) { this.props.onSubmit(value); } /** * Renders Cancel button. * * @private * @returns {*} The Cancel button if enabled and dialog is not modal. */ _renderCancelButton() { if (this.props.cancelDisabled || this.props.isModal) { return null; } return ( { this.props.t(this.props.cancelTitleKey || 'dialog.Cancel') } ); } /** * Renders component in dialog footer. * * @private * @returns {ReactElement} */ _renderFooter() { return ( ); } /** * Renders component in dialog header. * * @private * @returns {ReactElement} */ _renderHeader() { const { t } = this.props; return (

{ this.props.titleString || t(this.props.titleKey) }

); } /** * Renders OK button. * * @private * @returns {*} The OK button if enabled. */ _renderOKButton() { if (this.props.submitDisabled) { return null; } return ( { this.props.t(this.props.okTitleKey || 'dialog.Ok') } ); } /** * Sets the instance variable for the div containing the component's dialog * element so it can be accessed directly. * * @param {Object} element - The DOM element for the component's dialog. * @private * @returns {void} */ _setDialogElement(element) { this._dialogElement = element; } /** * Handles 'Enter' key in the dialog to submit/hide dialog depending on * the available buttons and their disabled state. * * @param {Object} event - The key event. * @private * @returns {void} */ _onKeyDown(event) { // If the event coming to the dialog has been subject to preventDefault // we don't handle it here. if (event.defaultPrevented) { return; } if (event.key === 'Enter') { event.preventDefault(); event.stopPropagation(); if (this.props.submitDisabled && !this.props.cancelDisabled) { this._onCancel(); } else if (!this.props.okDisabled) { this._onSubmit(); } } } /** * Updates focused button, if we have a reference to the dialog element. * Focus on available button if there is no focus already. * * @private * @returns {void} */ _updateButtonFocus() { if (this._dialogElement) { // if we have a focused element inside the dialog, skip changing // the focus if (this._dialogElement.contains(document.activeElement)) { return; } let buttonToFocus; if (this.props.submitDisabled) { buttonToFocus = this._dialogElement .querySelector(`[id=${CANCEL_BUTTON_ID}]`); } else if (!this.props.okDisabled) { buttonToFocus = this._dialogElement .querySelector(`[id=${OK_BUTTON_ID}]`); } if (buttonToFocus) { buttonToFocus.focus(); } } } } export default translate(StatelessDialog);