import { React, PropTypes, classnames } from '@gravityforms/libraries';
import { IdProvider, useIdContext } from '@gravityforms/react-utils';
import { spacerClasses } from '@gravityforms/utils';
import Heading from '../../elements/Heading';
import GridColumns from './GridColumns';
import GridControls from './GridControls';
import GridEmpty from './GridEmpty';
import GridRow from './GridRow';
import { getModules } from './utils';
const { forwardRef } = React;
/**
* @module DataGridComponent
* @description Renders a complex Data Grid component.
*
* @since 3.3.0
*
* @param {object} props Component props.
* @param {object|null} ref Ref to the component.
*
* @return {JSX.Element} The DataGrid component.
*/
const DataGridComponent = forwardRef( ( props, ref ) => {
const {
afterGridHeading = null,
columns = [],
customAttributes = {},
customClasses = [],
data = [],
dataPerPage = 20,
equalGrid = false,
gridControlWrapperClasses = [],
highlightHover = true,
highlightSelected = true,
i18n = {},
isLoading = false,
maintainHeight = false,
modules = [],
spacing = '',
titleAttributes = {},
titleClasses = [],
} = props;
const { gridHeadingI18n = '' } = i18n;
const id = useIdContext();
const {
BulkActions,
GridPagination,
ActiveFilters,
} = getModules( modules, [ 'BulkActions', 'GridPagination', 'ActiveFilters' ] );
let displayedData = data;
if ( maintainHeight && data.length < dataPerPage ) {
const fillerRows = Array.from( { length: dataPerPage - displayedData.length } ).map( () => ( {} ) );
displayedData = [ ...displayedData, ...fillerRows ];
}
const componentProps = {
className: classnames( {
'gform-data-grid': true,
'gform-data-grid--highlight-hover': highlightHover,
'gform-data-grid--highlight-selected': highlightSelected,
'gform-data-grid--equal-grid': equalGrid,
'gform-data-grid--loading': isLoading,
'gform-data-grid--empty': data.length === 0,
...spacerClasses( spacing ),
}, customClasses ),
ref,
id,
...customAttributes,
};
const titleProps = {
customClasses: classnames( {
'gform-data-grid__title': true,
}, titleClasses ),
size: 'text-lg',
tagName: 'h3',
weight: 'medium',
...titleAttributes,
};
const columnStyles = columns.map( ( column, index ) =>
column.hideAt
? `@media (max-width: ${ column.hideAt }px) { #${ id } .gform-data-grid__column-${ index } { display: none; } }`
: ''
).join( '\n' );
return (
<>
<style>{ columnStyles }</style>
<article { ...componentProps }>
{ ( gridHeadingI18n || afterGridHeading ) && (
<header className="gform-data-grid__header">
{ gridHeadingI18n && <Heading { ...titleProps }>{ gridHeadingI18n }</Heading> }
{ afterGridHeading }
</header>
) }
<GridControls
{ ...props }
displayedData={ displayedData }
wrapperClasses={ gridControlWrapperClasses }
/>
{ ActiveFilters && <ActiveFilters.ActiveFilters { ...props } /> }
<GridColumns
{ ...props }
location="header"
displayedData={ displayedData }
gridId={ id }
/>
{ BulkActions && <BulkActions.BulkSelectNotice { ...props } /> }
<div className="gform-data-grid__data">
{ displayedData.map( ( row, rowIndex ) => (
<GridRow
{ ...props }
key={ `${ id }-gform-data-grid__data-row--${ rowIndex }` }
row={ row }
rowIndex={ rowIndex }
displayedData={ displayedData }
gridId={ id }
/>
) ) }
<GridEmpty { ...props } />
</div>
<GridColumns
{ ...props }
location="footer"
displayedData={ displayedData }
gridId={ id }
/>
{ GridPagination && <GridPagination.GridPagination { ...props } /> }
</article>
</>
);
} );
/**
* @module DataGrid
* @description Renders a complex Data Grid component with id wrapper.
*
* @since 3.3.0
*
* @param {object} props Component props.
* @param {JSX.Element} props.afterGridHeading Element to render after the grid heading.
* @param {object} props.columns Array of column objects. Supply: component, key, props, sortable (optional), hideAt (optional). Key is used to match data keys for cells.
* @param {object} props.columnRowAttributes Custom attributes for the column row.
* @param {string|Array|object} props.columnRowClasses Custom classes for the column row.
* @param {object} props.columnStyleProps Style props for the column.
* @param {object} props.customAttributes Custom attributes for the component
* @param {string|Array|object} props.customClasses Custom classes for the component.
* @param {object} props.data The data for the component.
* @param {number} props.dataPerPage The number of data rows to show per page.
* @param {object} props.dataRowAttributes Custom attributes for the data row.
* @param {string|Array|object} props.dataRowClasses Custom classes for the data row.
* @param {string} props.dataRowMinHeight The minimum height for the data row.
* @param {JSX.Element} props.EmptyImage The image to show when there is no data.
* @param {boolean} props.emptyMessageAttributes Custom attributes for the empty message.
* @param {string|Array|object} props.emptyMessageClasses Custom classes for the empty message.
* @param {boolean} props.equalGrid Whether the grid should be equal.
* @param {string|Array|object} props.gridControlWrapperClasses Custom classes for the grid control wrapper.
* @param {boolean} props.gridLocked Whether the grid should be locked.
* @param {Function} props.handleGridClicks Passed handler for grid clicks if the field type supports it.
* @param {boolean} props.highlightHover Whether the grid should highlight a row on hover.
* @param {boolean} props.highlightSelected Whether the grid should highlight a selected row.
* @param {object} props.i18n Language strings for the component.
* @param {string} props.i18n.emptyMessageI18n The empty message for the data grid.
* @param {string} props.i18n.emptyTitleI18n The empty title for the data grid.
* @param {string} props.i18n.gridHeadingI18n The heading for the data grid.
* @param {string} props.id The ID for the component.
* @param {boolean} props.isLoading Whether the data grid is loading.
* @param {boolean} props.maintainHeight Whether the grid should maintain height at all times.
* @param {Array} props.modules The modules for the data grid.
* @param {object} props.moduleAttributes Custom attributes for the modules.
* @param {object} props.moduleState The state for the modules.
* @param {Function} props.setGridData Passed handler for field changes if the field type supports it.
* @param {Function} props.setIsLoading Handler to update the loading state.
* @param {boolean} props.showColumns Whether to show the column row(s).
* @param {boolean} props.showColumnsInFooter Whether the column row should be in the footer as well.
* @param {boolean} props.sortable Whether the grid should be sortable.
* @param {string|number|Array|object} props.spacing The spacing for the component, as a string, number, array, or object.
* @param {object} props.titleAttributes Custom attributes for the title.
* @param {string|Array|object} props.titleClasses Custom classes for the title.
* @param {Function} props.updateModuleState Handler to update the module state.
* @param {boolean} props.useAjax Whether to use ajax for the data grid.
* @param {object|null} ref Ref to the component.
*
* @return {JSX.Element} The DataGrid component.
*
* @example
* import DataGrid from '@gravityforms/components/react/admin/modules/DataGrid';
*
* return <DataGrid />;
*
*/
const DataGrid = forwardRef( ( props, ref ) => {
const defaultProps = {
afterGridHeading: null,
columns: [],
columnRowAttributes: {},
columnRowClasses: [],
columnStyleProps: {},
customAttributes: {},
customClasses: [],
data: [],
dataPerPage: 20,
dataRowAttributes: {},
dataRowClasses: [],
dataRowMinHeight: '71px',
EmptyImage: null,
emptyMessageAttributes: {},
emptyMessageClasses: [],
equalGrid: false,
gridControlWrapperClasses: [],
gridLocked: false,
handleGridClicks: () => {},
highlightHover: true,
highlightSelected: true,
i18n: {},
id: '',
isLoading: false,
maintainHeight: false,
modules: [],
moduleAttributes: {},
moduleState: {},
setGridData: () => {},
setIsLoading: () => {},
showColumns: true,
showColumnsInFooter: true,
sortable: false,
spacing: '',
titleAttributes: {},
titleClasses: [],
updateModuleState: () => {},
useAjax: false,
};
const combinedProps = { ...defaultProps, ...props };
const { id: idProp = '' } = combinedProps;
const idProviderProps = { id: idProp };
return (
<IdProvider { ...idProviderProps }>
<DataGridComponent { ...combinedProps } ref={ ref } />
</IdProvider>
);
} );
DataGrid.propTypes = {
afterGridHeading: PropTypes.node,
columns: PropTypes.arrayOf(
PropTypes.shape( {
key: PropTypes.string.isRequired,
component: PropTypes.string.isRequired,
props: PropTypes.object,
sortable: PropTypes.bool,
hideAt: PropTypes.number,
} )
),
columnRowAttributes: PropTypes.object,
columnRowClasses: PropTypes.oneOfType( [
PropTypes.string,
PropTypes.array,
PropTypes.object,
] ),
columnStyleProps: PropTypes.object,
customAttributes: PropTypes.object,
customClasses: PropTypes.oneOfType( [
PropTypes.string,
PropTypes.array,
PropTypes.object,
] ),
data: PropTypes.arrayOf( PropTypes.object ),
dataPerPage: PropTypes.number,
dataRowAttributes: PropTypes.object,
dataRowClasses: PropTypes.oneOfType( [
PropTypes.string,
PropTypes.array,
PropTypes.object,
] ),
dataRowMinHeight: PropTypes.string,
EmptyImage: PropTypes.oneOfType( [
PropTypes.node,
PropTypes.func,
PropTypes.object,
] ),
emptyMessageAttributes: PropTypes.object,
emptyMessageClasses: PropTypes.oneOfType( [
PropTypes.string,
PropTypes.array,
PropTypes.object,
] ),
equalGrid: PropTypes.bool,
gridControlWrapperClasses: PropTypes.oneOfType( [
PropTypes.string,
PropTypes.array,
PropTypes.object,
] ),
gridLocked: PropTypes.bool,
handleGridClicks: PropTypes.func,
highlightHover: PropTypes.bool,
highlightSelected: PropTypes.bool,
i18n: PropTypes.object,
id: PropTypes.string,
isLoading: PropTypes.bool,
maintainHeight: PropTypes.bool,
modules: PropTypes.arrayOf( PropTypes.object ),
moduleAttributes: PropTypes.object,
moduleState: PropTypes.object,
setGridData: PropTypes.func,
setIsLoading: PropTypes.func,
showColumns: PropTypes.bool,
showColumnsInFooter: PropTypes.bool,
sortable: PropTypes.bool,
spacing: PropTypes.oneOfType( [
PropTypes.string,
PropTypes.number,
PropTypes.array,
PropTypes.object,
] ),
titleAttributes: PropTypes.object,
titleClasses: PropTypes.oneOfType( [
PropTypes.string,
PropTypes.array,
PropTypes.object,
] ),
updateModuleState: PropTypes.func,
useAjax: PropTypes.bool,
};
DataGrid.displayName = 'DataGrid';
export default DataGrid;