// tslint:disable:max-classes-per-file import * as React from 'react'; import { PanelItemContext, PanelItemProp, PanelItemProps, PanelItemTemplate, PanelRenderProps, PanelTemplateProps, } from './Panel'; /** * a row context only knows about its row number * NOTE: the inherited index always has the same value as the row */ export interface GridRowContext extends PanelItemContext { row: number; } /** * a column context knows both its row number and column number * the index represents the index of the panel item being rendered */ export interface GridColumnContext extends GridRowContext { column: number; } /** * a layout element represents props for a component that helps define * the grid layout (i.e. GridRowDefinitions and RowDefinition) */ export interface GridLayoutElementProps< T = {}, TContext extends GridRowContext = GridRowContext > extends PanelItemProps, PanelTemplateProps, PanelRenderProps {} /** * a row layout element with a height prop */ export interface RowDefinitionProps extends GridLayoutElementProps { height?: number; } /** * a component to define a grid row, optionally with a static height value * if height is omitted, height will auto stretch to consume available space */ export class RowDefinition extends React.Component {} /** * a row collection layout element to define row layout elements as children */ export interface GridRowDefinitionsProps extends GridLayoutElementProps { children?: | React.ReactElement> | Array>>; } /** * a component to define the row layout component collection */ export class GridRowDefinitions extends React.Component< GridRowDefinitionsProps > {} /** * a column layout element with a width prop * width can be a ratio represented as a string (i.e., '1*' for 1 unit) * NOTE: if using multiple stretch columns, the number of units used * becomes the divisor (i.e., '1*', '2*', '4*' to denote 1/7, 2/7, 4/7) */ export interface ColumnDefinitionProps extends GridLayoutElementProps { width?: number | string; } /** * a component to define a grid column, optionally with a width value * if width is omitted, width will auto stretch to consume '1*' of space */ export class ColumnDefinition extends React.Component { static defaultProps: Partial = { width: '*', }; } /** * a column collection layout element to define column layout elements as children */ export interface GridColumnDefinitionsProps extends GridLayoutElementProps { children?: | React.ReactElement> | Array>>; } /** * a component to define the column layout component collection */ export class GridColumnDefinitions extends React.Component< GridColumnDefinitionsProps > {} export type GridLayoutDefinitionGroupElement = React.ReactElement< GridRowDefinitionsProps | GridColumnDefinitionsProps >; export type GridLayoutDefinitionElement = React.ReactElement< RowDefinitionProps | ColumnDefinitionProps >; /** * this class is used internally to compute the grid layout metadata */ export class GridLayoutDefinition { public static generateKey(row: number, column?: number) { return `${row}.${column || ''}`; } public readonly amount: number | undefined; public readonly stretch: boolean; public readonly itemClassName: | PanelItemProp | undefined; public readonly itemStyle: | PanelItemProp | undefined; public readonly itemProps: | PanelItemProp<{}, GridRowContext | GridColumnContext> | undefined; public readonly compact: boolean | undefined; public readonly itemTemplate: | PanelItemTemplate | undefined; constructor( definition?: GridLayoutDefinitionElement, definitionGroup?: GridLayoutDefinitionGroupElement, ) { const { val, type } = this.getLayoutParam(definition); let { amount, stretch } = this.getAmountAndStretch(val); if (type === RowDefinition && stretch === true) { amount = undefined; stretch = false; } else if ( type === ColumnDefinition && amount == null && stretch === true ) { amount = 1; } this.amount = amount; this.stretch = stretch; if (definitionGroup != null) { this.itemClassName = definitionGroup.props.itemClassName; this.itemStyle = definitionGroup.props.itemStyle; this.itemProps = definitionGroup.props.itemProps; this.compact = definitionGroup.props.compact; this.itemTemplate = definitionGroup.props.itemTemplate; } if (definition != null) { if (definition.props.itemClassName != null) { this.itemClassName = definition.props.itemClassName; } if (definition.props.itemStyle != null) { this.itemStyle = definition.props.itemStyle; } if (definition.props.itemProps != null) { this.itemProps = definition.props.itemProps; } if (definition.props.compact != null) { this.compact = definition.props.compact; } if (definition.props.itemTemplate != null) { this.itemTemplate = definition.props.itemTemplate; } } } protected getAmountAndStretch(val: string | number | undefined) { if (String.isString(val)) { if (val === '*') { return { amount: 1, stretch: true }; } else if (val.length > 1) { if (val[val.length - 1] === '*') { return { amount: parseInt(val), stretch: true }; } else { return { amount: parseInt(val), stretch: false }; } } else { return { amount: parseInt(val), stretch: false }; } } else if (val != null) { return { amount: val, stretch: false }; } else { return { amount: undefined, stretch: true }; } } protected getLayoutParam(definition?: GridLayoutDefinitionElement) { if ( definition != null && React.isValidElement( definition, ) ) { return { val: definition.props.height || definition.props.width, type: definition.type, }; } else { return { val: undefined, type: undefined }; } } }