UNPKG

react-cm-ui

Version:
238 lines (208 loc) 8.31 kB
import _ from 'lodash'; import ClassNames from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; import ReactDOM from 'react-dom'; import { columnPropTypesShape, columnPropsPropTypesShape, } from './detailsWindowPropTypes'; import { UI_CLASS_NAME, } from '../../global/constants'; import InfoBar from '../infoBar'; import DetailsWindowColumnContainer from './detailsWindowColumnContainer'; import domUtils from '../../utils/domUtils'; const propTypes = { bleed: PropTypes.bool, className: PropTypes.string, color: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]), columnProps: columnPropsPropTypesShape, columns: PropTypes.arrayOf(columnPropTypesShape).isRequired, data: PropTypes.shape({}).isRequired, /** * Used for DOM testing. https://testing-library.com/docs/queries/bytestid/ */ dataTestId: PropTypes.string, expandableColumns: PropTypes.arrayOf(columnPropTypesShape), forwardedRef: PropTypes.oneOfType([ PropTypes.func, PropTypes.shape({ current: PropTypes.instanceOf(Element), }), ]), moduleType: PropTypes.string, style: PropTypes.shape({}), }; const defaultProps = { bleed: true, className: undefined, color: undefined, columnProps: undefined, dataTestId: `${UI_CLASS_NAME}-details_window`, expandableColumns: undefined, forwardedRef: undefined, moduleType: undefined, style: {}, }; class DetailsWindow extends React.PureComponent { constructor() { super(); this.state = { isExpanded: false, }; this.expandableContainerHeight = null; this.onExpandButtonToggle = this.onExpandButtonToggle.bind(this); this.onExpandTransitionComplete = this.onExpandTransitionComplete.bind(this); this.previousExpandableContainerHeight = null; this.setColumnContainerHeight = this.setColumnContainerHeight.bind(this); } componentDidMount() { this.toggleExpandableContainer(); } componentDidUpdate(prevProps) { const { expandableColumns } = this.props; const { expandableColumns: prevExpandableColumns } = prevProps; if (_.isEmpty(prevExpandableColumns) && !_.isEmpty(expandableColumns)) { this.toggleExpandableContainer(); } } onExpandButtonToggle() { this.setState((prevState) => ({ isExpanded: !prevState.isExpanded, }), () => { this.toggleExpandableContainer(); }); } onExpandTransitionComplete() { const { moduleType } = this.props; const bemClassName = `${moduleType}--details_window`; const exandableContainer = ReactDOM.findDOMNode(this.exandableContainerRef); // eslint-disable-line react/no-find-dom-node, max-len exandableContainer.classList.remove( `${bemClassName}_exapndable_columns_container-contracted-active`, `${bemClassName}_exapndable_columns_container-expanded-active`, ); exandableContainer.removeEventListener( domUtils.cssTransitionType(exandableContainer), this.onExpandTransitionComplete, ); } setColumnContainerHeight(height) { if (_.isNil(this.expandableContainerHeight) || this.expandableContainerHeight > height) { this.expandableContainerHeight = height; } } toggleExpandableContainer() { const { expandableColumns, moduleType } = this.props; const bemClassName = `${moduleType}--details_window`; const { isExpanded } = this.state; const hasExpandableColumns = !_.isEmpty(expandableColumns); if (hasExpandableColumns && this.exandableContainerRef) { const exandableContainer = ReactDOM.findDOMNode(this.exandableContainerRef); // eslint-disable-line react/no-find-dom-node, max-len exandableContainer.style.height = `${isExpanded ? this.expandableContainerHeight : 0}px`; exandableContainer.classList.add( `${bemClassName}_exapndable_columns_container-${isExpanded ? 'expanded' : 'contracted'}-active`, ); exandableContainer.addEventListener( domUtils.cssTransitionType(exandableContainer), this.onExpandTransitionComplete, ); } } render() { const { bleed, className, color, columnProps, columns, data, dataTestId, expandableColumns, forwardedRef, style, moduleType, } = this.props; const { isExpanded } = this.state; const hasExpandableColumns = !_.isEmpty(expandableColumns); const bemClassName = `${moduleType}--details_window`; const containerClasses = ClassNames('ui', bemClassName, className, { [`${bemClassName}-bleed`]: bleed, }); let detailsColumnKeyNum = 1; let detailsColumnKeyNumExpanded = 1; let horizontalSpacing; if (columnProps) { horizontalSpacing = columnProps.horizontalSpacing; } let expandableJSX; if (hasExpandableColumns) { const shouldShowExpanded = isExpanded; const expandableColumnsContainerName = `${bemClassName}_exapndable_columns_container`; const expandableContainerClasses = ClassNames( expandableColumnsContainerName, { [`${expandableColumnsContainerName}-expanded`]: shouldShowExpanded, [`${expandableColumnsContainerName}-contracted`]: !shouldShowExpanded, }, ); expandableJSX = ( <div className={expandableContainerClasses} ref={(ref) => { this.exandableContainerRef = ref; }} > {_.map(expandableColumns, (column) => { detailsColumnKeyNumExpanded += 1; return ( <DetailsWindowColumnContainer column={column} columnProps={columnProps} data={data} key={`${moduleType}DetailsColumn-${detailsColumnKeyNumExpanded}`} moduleType={moduleType} setColumnContainerHeight={this.setColumnContainerHeight} /> ); })} </div> ); } return ( <div className={containerClasses} data-testid={dataTestId} ref={forwardedRef} style={style} > <InfoBar color={color}> <div className={`${bemClassName}_columns_container`} style={{ marginLeft: horizontalSpacing ? `-${horizontalSpacing}px` : null, marginRight: horizontalSpacing ? `-${horizontalSpacing}px` : null, }} > {_.map(columns, (column) => { detailsColumnKeyNum += 1; return ( <DetailsWindowColumnContainer column={column} columnProps={columnProps} data={data} isExpanded={isExpanded} key={`${moduleType}DetailsColumn-${detailsColumnKeyNum}`} moduleType={moduleType} onExpandButtonToggle={this.onExpandButtonToggle} /> ); })} </div> {expandableJSX} </InfoBar> </div> ); } } DetailsWindow.propTypes = propTypes; DetailsWindow.defaultProps = defaultProps; export default DetailsWindow;