@mui/x-data-grid
Version:
The community edition of the data grid component (MUI X).
320 lines (314 loc) • 15.2 kB
JavaScript
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _extends from "@babel/runtime/helpers/esm/extends";
import * as React from 'react';
import { useGridApiMethod } from '../../utils/useGridApiMethod';
import { useGridLogger } from '../../utils/useGridLogger';
import { gridColumnFieldsSelector, gridColumnDefinitionsSelector, gridColumnLookupSelector, gridColumnsStateSelector, gridColumnVisibilityModelSelector, gridVisibleColumnDefinitionsSelector, gridColumnPositionsSelector } from './gridColumnsSelector';
import { GridSignature, useGridApiEventHandler } from '../../utils/useGridApiEventHandler';
import { useGridRegisterPipeProcessor, useGridRegisterPipeApplier } from '../../core/pipeProcessing';
import { hydrateColumnsWidth, createColumnsState, mergeColumnsState, COLUMNS_DIMENSION_PROPERTIES } from './gridColumnsUtils';
import { GridPreferencePanelsValue } from '../preferencesPanel';
import { getGridDefaultColumnTypes } from '../../../colDef';
import { jsx as _jsx } from "react/jsx-runtime";
var defaultColumnTypes = getGridDefaultColumnTypes();
export var columnsStateInitializer = function columnsStateInitializer(state, props, apiRef) {
var _props$initialState, _ref, _props$columnVisibili, _props$initialState2;
var columnsState = createColumnsState({
apiRef: apiRef,
columnTypes: defaultColumnTypes,
columnsToUpsert: props.columns,
initialState: (_props$initialState = props.initialState) == null ? void 0 : _props$initialState.columns,
columnVisibilityModel: (_ref = (_props$columnVisibili = props.columnVisibilityModel) != null ? _props$columnVisibili : (_props$initialState2 = props.initialState) == null || (_props$initialState2 = _props$initialState2.columns) == null ? void 0 : _props$initialState2.columnVisibilityModel) != null ? _ref : {},
keepOnlyColumnsToUpsert: true
});
return _extends({}, state, {
columns: columnsState
});
};
/**
* @requires useGridParamsApi (method)
* @requires useGridDimensions (method, event) - can be after
* TODO: Impossible priority - useGridParamsApi also needs to be after useGridColumns
*/
export function useGridColumns(apiRef, props) {
var _props$initialState4, _props$slotProps2;
var logger = useGridLogger(apiRef, 'useGridColumns');
var columnTypes = defaultColumnTypes;
var previousColumnsProp = React.useRef(props.columns);
var previousColumnTypesProp = React.useRef(columnTypes);
apiRef.current.registerControlState({
stateId: 'visibleColumns',
propModel: props.columnVisibilityModel,
propOnChange: props.onColumnVisibilityModelChange,
stateSelector: gridColumnVisibilityModelSelector,
changeEvent: 'columnVisibilityModelChange'
});
var setGridColumnsState = React.useCallback(function (columnsState) {
logger.debug('Updating columns state.');
apiRef.current.setState(mergeColumnsState(columnsState));
apiRef.current.forceUpdate();
apiRef.current.publishEvent('columnsChange', columnsState.orderedFields);
}, [logger, apiRef]);
/**
* API METHODS
*/
var getColumn = React.useCallback(function (field) {
return gridColumnLookupSelector(apiRef)[field];
}, [apiRef]);
var getAllColumns = React.useCallback(function () {
return gridColumnDefinitionsSelector(apiRef);
}, [apiRef]);
var getVisibleColumns = React.useCallback(function () {
return gridVisibleColumnDefinitionsSelector(apiRef);
}, [apiRef]);
var getColumnIndex = React.useCallback(function (field) {
var useVisibleColumns = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
var columns = useVisibleColumns ? gridVisibleColumnDefinitionsSelector(apiRef) : gridColumnDefinitionsSelector(apiRef);
return columns.findIndex(function (col) {
return col.field === field;
});
}, [apiRef]);
var getColumnPosition = React.useCallback(function (field) {
var index = getColumnIndex(field);
return gridColumnPositionsSelector(apiRef)[index];
}, [apiRef, getColumnIndex]);
var setColumnVisibilityModel = React.useCallback(function (model) {
var currentModel = gridColumnVisibilityModelSelector(apiRef);
if (currentModel !== model) {
apiRef.current.setState(function (state) {
return _extends({}, state, {
columns: createColumnsState({
apiRef: apiRef,
columnTypes: columnTypes,
columnsToUpsert: [],
initialState: undefined,
columnVisibilityModel: model,
keepOnlyColumnsToUpsert: false
})
});
});
apiRef.current.forceUpdate();
}
}, [apiRef, columnTypes]);
var updateColumns = React.useCallback(function (columns) {
var columnsState = createColumnsState({
apiRef: apiRef,
columnTypes: columnTypes,
columnsToUpsert: columns,
initialState: undefined,
keepOnlyColumnsToUpsert: false
});
setGridColumnsState(columnsState);
}, [apiRef, setGridColumnsState, columnTypes]);
var setColumnVisibility = React.useCallback(function (field, isVisible) {
var _columnVisibilityMode;
var columnVisibilityModel = gridColumnVisibilityModelSelector(apiRef);
var isCurrentlyVisible = (_columnVisibilityMode = columnVisibilityModel[field]) != null ? _columnVisibilityMode : true;
if (isVisible !== isCurrentlyVisible) {
var newModel = _extends({}, columnVisibilityModel, _defineProperty({}, field, isVisible));
apiRef.current.setColumnVisibilityModel(newModel);
}
}, [apiRef]);
var getColumnIndexRelativeToVisibleColumns = React.useCallback(function (field) {
var allColumns = gridColumnFieldsSelector(apiRef);
return allColumns.findIndex(function (col) {
return col === field;
});
}, [apiRef]);
var setColumnIndex = React.useCallback(function (field, targetIndexPosition) {
var allColumns = gridColumnFieldsSelector(apiRef);
var oldIndexPosition = getColumnIndexRelativeToVisibleColumns(field);
if (oldIndexPosition === targetIndexPosition) {
return;
}
logger.debug("Moving column ".concat(field, " to index ").concat(targetIndexPosition));
var updatedColumns = _toConsumableArray(allColumns);
var fieldRemoved = updatedColumns.splice(oldIndexPosition, 1)[0];
updatedColumns.splice(targetIndexPosition, 0, fieldRemoved);
setGridColumnsState(_extends({}, gridColumnsStateSelector(apiRef.current.state), {
orderedFields: updatedColumns
}));
var params = {
column: apiRef.current.getColumn(field),
targetIndex: apiRef.current.getColumnIndexRelativeToVisibleColumns(field),
oldIndex: oldIndexPosition
};
apiRef.current.publishEvent('columnIndexChange', params);
}, [apiRef, logger, setGridColumnsState, getColumnIndexRelativeToVisibleColumns]);
var setColumnWidth = React.useCallback(function (field, width) {
var _apiRef$current$getRo, _apiRef$current$getRo2;
logger.debug("Updating column ".concat(field, " width to ").concat(width));
var columnsState = gridColumnsStateSelector(apiRef.current.state);
var column = columnsState.lookup[field];
var newColumn = _extends({}, column, {
width: width,
hasBeenResized: true
});
setGridColumnsState(hydrateColumnsWidth(_extends({}, columnsState, {
lookup: _extends({}, columnsState.lookup, _defineProperty({}, field, newColumn))
}), (_apiRef$current$getRo = (_apiRef$current$getRo2 = apiRef.current.getRootDimensions()) == null ? void 0 : _apiRef$current$getRo2.viewportInnerSize.width) != null ? _apiRef$current$getRo : 0));
apiRef.current.publishEvent('columnWidthChange', {
element: apiRef.current.getColumnHeaderElement(field),
colDef: newColumn,
width: width
});
}, [apiRef, logger, setGridColumnsState]);
var columnApi = {
getColumn: getColumn,
getAllColumns: getAllColumns,
getColumnIndex: getColumnIndex,
getColumnPosition: getColumnPosition,
getVisibleColumns: getVisibleColumns,
getColumnIndexRelativeToVisibleColumns: getColumnIndexRelativeToVisibleColumns,
updateColumns: updateColumns,
setColumnVisibilityModel: setColumnVisibilityModel,
setColumnVisibility: setColumnVisibility,
setColumnWidth: setColumnWidth
};
var columnReorderApi = {
setColumnIndex: setColumnIndex
};
useGridApiMethod(apiRef, columnApi, 'public');
useGridApiMethod(apiRef, columnReorderApi, props.signature === GridSignature.DataGrid ? 'private' : 'public');
/**
* PRE-PROCESSING
*/
var stateExportPreProcessing = React.useCallback(function (prevState, context) {
var _props$initialState$c, _props$initialState3;
var columnsStateToExport = {};
var columnVisibilityModelToExport = gridColumnVisibilityModelSelector(apiRef);
var shouldExportColumnVisibilityModel =
// Always export if the `exportOnlyDirtyModels` property is not activated
!context.exportOnlyDirtyModels ||
// Always export if the model is controlled
props.columnVisibilityModel != null ||
// Always export if the model has been initialized
// TODO v6 Do a nullish check instead to export even if the initial model equals "{}"
Object.keys((_props$initialState$c = (_props$initialState3 = props.initialState) == null || (_props$initialState3 = _props$initialState3.columns) == null ? void 0 : _props$initialState3.columnVisibilityModel) != null ? _props$initialState$c : {}).length > 0 ||
// Always export if the model is not empty
Object.keys(columnVisibilityModelToExport).length > 0;
if (shouldExportColumnVisibilityModel) {
columnsStateToExport.columnVisibilityModel = columnVisibilityModelToExport;
}
columnsStateToExport.orderedFields = gridColumnFieldsSelector(apiRef);
var columns = gridColumnDefinitionsSelector(apiRef);
var dimensions = {};
columns.forEach(function (colDef) {
if (colDef.hasBeenResized) {
var colDefDimensions = {};
COLUMNS_DIMENSION_PROPERTIES.forEach(function (propertyName) {
var propertyValue = colDef[propertyName];
if (propertyValue === Infinity) {
propertyValue = -1;
}
colDefDimensions[propertyName] = propertyValue;
});
dimensions[colDef.field] = colDefDimensions;
}
});
if (Object.keys(dimensions).length > 0) {
columnsStateToExport.dimensions = dimensions;
}
return _extends({}, prevState, {
columns: columnsStateToExport
});
}, [apiRef, props.columnVisibilityModel, (_props$initialState4 = props.initialState) == null ? void 0 : _props$initialState4.columns]);
var stateRestorePreProcessing = React.useCallback(function (params, context) {
var _context$stateToResto;
var columnVisibilityModelToImport = (_context$stateToResto = context.stateToRestore.columns) == null ? void 0 : _context$stateToResto.columnVisibilityModel;
var initialState = context.stateToRestore.columns;
if (columnVisibilityModelToImport == null && initialState == null) {
return params;
}
var columnsState = createColumnsState({
apiRef: apiRef,
columnTypes: columnTypes,
columnsToUpsert: [],
initialState: initialState,
columnVisibilityModel: columnVisibilityModelToImport,
keepOnlyColumnsToUpsert: false
});
apiRef.current.setState(mergeColumnsState(columnsState));
if (initialState != null) {
apiRef.current.publishEvent('columnsChange', columnsState.orderedFields);
}
return params;
}, [apiRef, columnTypes]);
var preferencePanelPreProcessing = React.useCallback(function (initialValue, value) {
if (value === GridPreferencePanelsValue.columns) {
var _props$slotProps;
var ColumnsPanel = props.slots.columnsPanel;
return /*#__PURE__*/_jsx(ColumnsPanel, _extends({}, (_props$slotProps = props.slotProps) == null ? void 0 : _props$slotProps.columnsPanel));
}
return initialValue;
}, [props.slots.columnsPanel, (_props$slotProps2 = props.slotProps) == null ? void 0 : _props$slotProps2.columnsPanel]);
var addColumnMenuItems = React.useCallback(function (columnMenuItems) {
if (props.disableColumnSelector) {
return columnMenuItems;
}
return [].concat(_toConsumableArray(columnMenuItems), ['columnMenuColumnsItem']);
}, [props.disableColumnSelector]);
useGridRegisterPipeProcessor(apiRef, 'columnMenu', addColumnMenuItems);
useGridRegisterPipeProcessor(apiRef, 'exportState', stateExportPreProcessing);
useGridRegisterPipeProcessor(apiRef, 'restoreState', stateRestorePreProcessing);
useGridRegisterPipeProcessor(apiRef, 'preferencePanel', preferencePanelPreProcessing);
/**
* EVENTS
*/
var prevInnerWidth = React.useRef(null);
var handleGridSizeChange = function handleGridSizeChange(viewportInnerSize) {
if (prevInnerWidth.current !== viewportInnerSize.width) {
prevInnerWidth.current = viewportInnerSize.width;
setGridColumnsState(hydrateColumnsWidth(gridColumnsStateSelector(apiRef.current.state), viewportInnerSize.width));
}
};
useGridApiEventHandler(apiRef, 'viewportInnerSizeChange', handleGridSizeChange);
/**
* APPLIERS
*/
var hydrateColumns = React.useCallback(function () {
logger.info("Columns pipe processing have changed, regenerating the columns");
var columnsState = createColumnsState({
apiRef: apiRef,
columnTypes: columnTypes,
columnsToUpsert: [],
initialState: undefined,
keepOnlyColumnsToUpsert: false
});
setGridColumnsState(columnsState);
}, [apiRef, logger, setGridColumnsState, columnTypes]);
useGridRegisterPipeApplier(apiRef, 'hydrateColumns', hydrateColumns);
/**
* EFFECTS
*/
// The effect do not track any value defined synchronously during the 1st render by hooks called after `useGridColumns`
// As a consequence, the state generated by the 1st run of this useEffect will always be equal to the initialization one
var isFirstRender = React.useRef(true);
React.useEffect(function () {
if (isFirstRender.current) {
isFirstRender.current = false;
return;
}
logger.info("GridColumns have changed, new length ".concat(props.columns.length));
if (previousColumnsProp.current === props.columns && previousColumnTypesProp.current === columnTypes) {
return;
}
var columnsState = createColumnsState({
apiRef: apiRef,
columnTypes: columnTypes,
initialState: undefined,
// If the user provides a model, we don't want to set it in the state here because it has it's dedicated `useEffect` which calls `setColumnVisibilityModel`
columnsToUpsert: props.columns,
keepOnlyColumnsToUpsert: true
});
previousColumnsProp.current = props.columns;
previousColumnTypesProp.current = columnTypes;
setGridColumnsState(columnsState);
}, [logger, apiRef, setGridColumnsState, props.columns, columnTypes]);
React.useEffect(function () {
if (props.columnVisibilityModel !== undefined) {
apiRef.current.setColumnVisibilityModel(props.columnVisibilityModel);
}
}, [apiRef, logger, props.columnVisibilityModel]);
}