/** * Container component for displaying cardPanel in a dynamic grid * allows you to configure the width, height, and position of the cardPanel, which are its descendants * * @author Brauer Ilya * @date 2020-04-15 */ import * as React from 'react'; import * as GridLayout from 'react-grid-layout'; import 'react-grid-layout/css/styles.css'; import 'react-resizable/css/styles.css'; import * as styles from './cardPanel.m.scss'; import {propsGetter} from '../../utils/propsGetter'; import {joinClassNames} from '../../index'; import debounce from 'lodash/debounce'; type IProps = { isDraggable?: boolean; isResizable?: boolean; onLayoutChange?: (layout: GridLayout.Layout []) => void; draggableHandle?: string; layout?: GridLayout.Layout []; margin?: [number, number]; cols?: number; } & Partial; const defaultProps = { rowHeight: 110, isDraggable: true, isResizable: true }; type DefaultProps = Readonly; const getProps = propsGetter(defaultProps); interface IState { width: number; } export type PanelGridLayout = GridLayout.Layout; export type GridActionCallback = GridLayout.ItemCallback; export class CardPanelGrid extends React.PureComponent { static defaultProps = defaultProps; gridLayoutContainer = React.createRef(); override state = { width: 0 }; constructor (props: IProps) { super(props); this.onWindowResize = debounce(this.onWindowResize.bind(this), 800, { leading: true, trailing: false }); } override componentDidMount (): void { this.calculateGridWidth(this.state.width); window.addEventListener('resize', this.onWindowResize); } override componentDidUpdate (prevProps: Readonly, prevState: Readonly, snapshot?: any): void { if (prevState.width !== 0) { this.calculateGridWidth(prevState.width); } } override componentWillUnmount (): void { window.removeEventListener('resize', this.onWindowResize); } onWindowResize = () => { if (this.gridLayoutContainer.current) { const width = this.gridLayoutContainer.current.clientWidth; this.setState({width}); } } calculateGridWidth (prevWidth: number) { if (this.gridLayoutContainer.current) { const width = this.gridLayoutContainer.current.clientWidth; if (width !== prevWidth) { this.setState({width}); } } } override render () { const {rowHeight} = getProps(this.props); const containerClassName = joinClassNames( [styles.gridLayout, Boolean(this.props.isDraggable || this.props.isResizable)] ); return (
{React.Children.map(this.props.children, (Child: React.ReactElement<{ dataGrid?: GridLayout.Layout; 'data-grid'?: GridLayout.Layout; }>, index) => { if (React.isValidElement(Child)) { let dataGrid: Partial = {}; const defaultItemProp: Partial = Child.props.dataGrid || Child.props['data-grid'] || {}; if (this.props.layout) { const grid = this.props.layout.find((item) => { return item.i === defaultItemProp.i || item.i === Child.key; }); if (grid) { dataGrid = grid; } else { dataGrid = defaultItemProp; } } return (
{Child}
); } return null; })}
); } }