UNPKG

wix-style-react

Version:
245 lines (225 loc) • 7.59 kB
import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import throttle from 'lodash/throttle'; import { generateDataAttr } from '../../utils/generateDataAttr'; import deprecationLog from '../../utils/deprecationLog'; import HeaderLayout from './HeaderLayout'; import FooterLayout from './FooterLayout'; import styles from './MessageBoxFunctionalLayout.scss'; class MessageBoxFunctionalLayout extends React.PureComponent { constructor(props) { super(props); deprecationLog( `Using "<MessageBoxFunctionalLayout/>" is deprecated. Instead, we advise you to use the newer "<MessageModalLayout/>" component. Please refer to it's documentation.`, ); this.state = { hasScroll: false, scrolledToBottom: false, }; this.messageBoxRef = null; } componentWillUnmount() { if (this.state.hasScroll) { this._handleMessageBoxScroll.cancel(); this.messageBoxRef.removeEventListener( 'scroll', this._handleMessageBoxScroll, ); } } _initializeMessageBoxRef = el => { if (el && el.scrollHeight > el.clientHeight) { this.setState({ hasScroll: true }); this.messageBoxRef = el; this.messageBoxRef.addEventListener( 'scroll', this._handleMessageBoxScroll, ); } }; _handleMessageBoxScroll = throttle(() => { const scrolledToBottom = this.messageBoxRef.scrollTop + this.messageBoxRef.clientHeight === this.messageBoxRef.scrollHeight; if (scrolledToBottom !== this.state.scrolledToBottom) { this.setState({ scrolledToBottom }); } }, 16); _renderContent = () => { const { children, hideFooter, noBodyPadding, maxHeight, fullscreen, withEmptyState, } = this.props; const { hasScroll, scrolledToBottom } = this.state; const messageBoxBodyClassNames = classNames(styles.body, { [styles.scrollable]: typeof maxHeight !== 'undefined', [styles.noPadding]: noBodyPadding, [styles.fullscreenBody]: fullscreen, [styles.noFooter]: hideFooter, [styles.footerBorder]: hasScroll && !scrolledToBottom, [styles.withEmptyState]: withEmptyState, }); const messageBoxBodyStyle = { maxHeight, }; return ( <div data-hook="message-box-body" className={messageBoxBodyClassNames} style={messageBoxBodyStyle} ref={this._initializeMessageBoxRef} > {children} </div> ); }; render() { const { theme } = this.props; const { dataHook, title, onCancel, onOk, onClose, confirmText, confirmPrefixIcon, confirmSuffixIcon, cancelText, cancelPrefixIcon, cancelSuffixIcon, buttonsHeight, hideFooter, footerBottomChildren, closeButton, disableConfirmation, disableCancel, width, margin, noBodyPadding, fullscreen, withEmptyState, sideActions, image, } = this.props; const contentClassName = classNames(styles.content, { [styles.fullscreenContent]: fullscreen, }); const imageClassName = classNames(styles.image, { [styles.withFooterAction]: sideActions, [styles.noPadding]: noBodyPadding, }); return ( <div data-hook={dataHook} className={contentClassName} style={{ width, margin }} {...generateDataAttr(this.props, ['noBodyPadding', 'theme'])} > <HeaderLayout title={title} onCancel={onClose ? onClose : onCancel} theme={theme} closeButton={closeButton} /> {image && !withEmptyState ? ( <div className={styles.messageWithImage}> <div className={imageClassName} children={image} /> {this._renderContent()} </div> ) : ( this._renderContent() )} {!hideFooter ? ( <FooterLayout bottomChildren={footerBottomChildren} enableCancel={!disableCancel} enableOk={!disableConfirmation} buttonsHeight={buttonsHeight} confirmText={confirmText} confirmPrefixIcon={confirmPrefixIcon} confirmSuffixIcon={confirmSuffixIcon} cancelText={cancelText} cancelPrefixIcon={cancelPrefixIcon} cancelSuffixIcon={cancelSuffixIcon} onCancel={onCancel} onOk={onOk} theme={theme} sideActions={sideActions} /> ) : null} </div> ); } } MessageBoxFunctionalLayout.propTypes = { /** applied as data-hook HTML attribute that can be used to create driver in testing */ dataHook: PropTypes.string, /** Hides the footer that contains the action buttons */ hideFooter: PropTypes.bool, /** Defines the main action button text */ confirmText: PropTypes.node, /** Add a prefix icon for the main action button */ confirmPrefixIcon: PropTypes.element, /** Add a suffix icon for the main action button */ confirmSuffixIcon: PropTypes.element, /** Defines the secondary action button text */ cancelText: PropTypes.node, /** Add a prefix icon for the secondary action button */ cancelPrefixIcon: PropTypes.element, /** Add a suffix icon for the secondary action button */ cancelSuffixIcon: PropTypes.element, /** modal theme color */ theme: PropTypes.oneOf(['red', 'blue', 'purple']), /** Called when the main action (confirm) is clicked */ onOk: PropTypes.func, /** Called when the secondary action (cancel) is clicked */ onCancel: PropTypes.func, /** Called when the close button is clicked */ onClose: PropTypes.func, /** Specify exact width */ width: PropTypes.string, /** Specify exact margin. Use to fine tune position inside other elements. * When used inside `<Modal>`, beware that `<Modal>` is a flex container, therefore specific flex item CSS rules apply for this margin. */ margin: PropTypes.string, /** Defines the modals's header title */ title: PropTypes.node, /** The content to be displayed. can be text or some node */ children: PropTypes.any, /** Max height. When supplied - will allow internal scroll to the component */ maxHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Defines the buttons size */ buttonsHeight: PropTypes.oneOf(['tiny', 'small', 'medium', 'large']), /** Show/hide the close button */ closeButton: PropTypes.bool, /** Defines the secondary action button */ disableCancel: PropTypes.bool, /** Defines the main action button */ disableConfirmation: PropTypes.bool, /** Removes the content padding. Used in custom modal that defines it's own padding*/ noBodyPadding: PropTypes.bool, /** A render slot to display a foot note */ footerBottomChildren: PropTypes.node, /** Stretches the component to a full screen mode (with some padding) */ fullscreen: PropTypes.bool, /** Changes the internal padding to be used with `<EmptyState/>` component */ withEmptyState: PropTypes.bool, /** Used to display some side component in the footer, for example `<Checkbox/>` */ sideActions: PropTypes.node, /** Used to display an illustration on the left side */ image: PropTypes.node, }; MessageBoxFunctionalLayout.defaultProps = { theme: 'blue', buttonsHeight: 'small', disableCancel: false, disableConfirmation: false, noBodyPadding: false, fullscreen: false, withEmptyState: false, }; export default MessageBoxFunctionalLayout;