/** * empty comment line Ivan Marshalkin * * @author: Ivan Marshalkin * @date: 2019-04-26 */ import * as React from 'react'; import {Button, Icon, joinClassNames, PLACEMENT, SIZE, Tooltip} from '../../index'; import {Resizer} from '../resizer/Resizer'; import * as styles from './cardPanel.m.scss'; import {CardPanelGrid} from './CardPanelGrid'; import {CardPanelGroup} from './CardPanelGroup'; type CardPanelTheme = 'default' | 'dark'; export type CardPanelFlexDirection = 'column' | // default value. render all children in column 'row' | // add flex to content, every children will be rendered in one row 'row-wrap' | // add grid to content. if @media < 1320, one column, if @media >= 1320 to columns (minmax(435px, 695px) minmax(435px, 695px)) 'row-resizable'; // the same as 'row', but add resizable for first element export type ResizerOptions = { minWidth?: number; maxWidth?: number; } export interface ICardPanelProps { children?: React.ReactNode; title?: React.ReactNode; titleTooltip?: string; internal?: boolean; // Minimalistic header isCollapsed?: boolean; hideOverflow?: boolean; leftExtraItems?: React.ReactNode; rightExtraItems?: React.ReactNode; noBodyPadding?: boolean; contentAutoHeight?: boolean; 'data-qaid'?: string; 'data-panel-id'?: string; onToggleCollapse?: (isCollapsed: boolean) => void; mountOnExpand?: boolean; // we mount children only when we open the panel theme?: CardPanelTheme; flexDirection?: CardPanelFlexDirection; isSticky?: boolean; isWide?: boolean; // by default, max-width of CardPanel is 695px, if isWide === true, width is 100% forwardRef?: React.RefObject; resizerOptions?: ResizerOptions; helperText?: React.ReactNode; helperTitle?: string; } interface IState { isCollapsed: boolean; isShowHelp: boolean; } const defaultProps = { hideOverflow: false }; export class CardPanel extends React.Component { static Group = CardPanelGroup; static Grid = CardPanelGrid; static defaultProps = defaultProps; private minResizerWidth?: number; DEFAULT_RESIZABLE_CONTENT_WIDTH = 400; resizerColumnRef = React.createRef(); override state: IState = { isCollapsed: true, isShowHelp: this.props.helperText ? true : false }; // public api expand () { this.setState({isCollapsed: false}); } get drawHeader () { return this.props.leftExtraItems || this.props.title || this.props.rightExtraItems; } get rightItems () { const {rightExtraItems, isCollapsed} = this.props; return ( {rightExtraItems && rightExtraItems} {isCollapsed !== undefined && (
)}
); } get renderContent () { const { internal, noBodyPadding, contentAutoHeight, title, leftExtraItems, rightExtraItems, flexDirection } = this.props; const classNames = joinClassNames( styles.cardContent, [styles.internal, internal === true], [styles.noBodyPadding, noBodyPadding === true], [styles.noOverflow, this.props.hideOverflow === true], [styles.contentAutoHeight, contentAutoHeight === true], [styles.isCollapsed, this.state.isCollapsed === true], [styles.withoutHeader, !title && !leftExtraItems && !rightExtraItems], [styles.flexRow, flexDirection === 'row' || flexDirection === 'row-wrap' || flexDirection === 'row-resizable'], [styles.flexColumn, flexDirection === 'column'], [styles.flexWrap, flexDirection === 'row-wrap'], 'scrollable' ); let children = this.props.children; if (flexDirection === 'row-resizable') { children = React.Children.map(this.props.children, (child, index) => { const childStyles = joinClassNames( styles.childContainer, [styles.resizableContainer, index === 0] ); if (index === 0) { return ( <>
{child}
); } return (
{child}
); }); } return (
{children}
); } get cardStyle () { const cardStyle = joinClassNames( styles.cardPanel, [styles.internal, this.props.internal === true], [styles.contentAutoHeight, this.props.contentAutoHeight === true], [styles.noHeader, !this.drawHeader], [styles.wide, this.props.isWide === true] ); return cardStyle; } get cardHeaderStyle () { const cardHeaderStyle = joinClassNames( styles.cardHeader, [styles.sticky, this.props.isSticky === true], [styles.themeDark, this.props.theme === 'dark'], [styles.themeLight, !this.props.theme || this.props.theme === 'default'], [styles.withLeftItems, Boolean(this.props.leftExtraItems)], [styles.withRightItems, Boolean(this.props.rightExtraItems)], [styles.isCollapsed, this.state.isCollapsed === true] ); return cardHeaderStyle; } get renderHelper () { const helperContainerStyle = joinClassNames( styles.helperContainer, [styles.showHelp, this.state.isShowHelp] ); return (
{this.state.isShowHelp && ( <>
{this.props.helperTitle && (
{this.props.helperTitle}
)}
{this.props.helperText}
); } private toggleHelp = () => { this.setState((prevState) => { return { isShowHelp: !prevState.isShowHelp }; }); } private setResizerDefaultWidth () { const el = this.resizerColumnRef?.current; if (el) { const width = this.getResizableWidth(el); el.style.setProperty('width', `${width}px`); this.minResizerWidth = width; } } override componentDidMount () { if (this.props.isCollapsed === undefined || this.props.isCollapsed === false) { this.setState({isCollapsed: false}); } this.setResizerDefaultWidth(); } override componentDidUpdate (prevProps: Readonly, prevState: Readonly, snapshot?: any): void { if ( prevProps.isCollapsed !== undefined && prevState.isCollapsed !== this.props.isCollapsed && this.props.isCollapsed !== undefined ) { this.setState({isCollapsed: this.props.isCollapsed}); } } handleCollapseClick = (e: React.SyntheticEvent) => { e.stopPropagation(); this.setState((prevState) => ({ isCollapsed: !prevState.isCollapsed }), () => { if (this.props.onToggleCollapse) { this.props.onToggleCollapse(this.state.isCollapsed); } }); }; private getResizableWidth (el: HTMLElement) { const resizableWidth = this.props.resizerOptions?.minWidth || this.DEFAULT_RESIZABLE_CONTENT_WIDTH; const width = Math.min(el.clientWidth, resizableWidth); return width; } override render () { const {title, leftExtraItems, isCollapsed, forwardRef, titleTooltip} = this.props; const leftExtraStyles = joinClassNames( styles.extraItemsContainer, styles.leftExtraItemsContainer ); return (
{this.props.mountOnExpand === true && this.state.isCollapsed === true ? null : this.renderContent} {this.drawHeader && (
{leftExtraItems && (
{leftExtraItems}
)} {titleTooltip !== undefined ? (
{title}
) : (
{title}
)}
{this.rightItems}
)} {this.props.helperText !== undefined && this.renderHelper}
); } }