163 lines
7.2 KiB
JavaScript
163 lines
7.2 KiB
JavaScript
const DEFAULT_WIDTH = 150;
|
|
const DEFAULT_MIN_WIDTH = 100;
|
|
/**
|
|
* This function takes the column definitions and the curent ColumnWidthState and returns new state.
|
|
* - It uses existing state for existing columns.
|
|
* - It removes any state for columns no longer present.
|
|
* - It checks if any column has been replaced and returns updated state if so
|
|
* - It returns old state if no changes in the state have been made (so that react doesn't call effects)
|
|
* @param columns
|
|
* @param state
|
|
* @returns
|
|
*/ export function columnDefinitionsToState(columns, state = [], columnSizingOptions = {}) {
|
|
let updated = false;
|
|
const stateMap = new Map(state.map((s)=>[
|
|
s.columnId,
|
|
s
|
|
]));
|
|
const updatedState = columns.map((column)=>{
|
|
const existingColumnState = stateMap.get(column.columnId);
|
|
if (existingColumnState) {
|
|
var _columnSizingOptions_column_columnId;
|
|
const { idealWidth = existingColumnState.idealWidth, minWidth = existingColumnState.minWidth, padding = existingColumnState.padding } = (_columnSizingOptions_column_columnId = columnSizingOptions[column.columnId]) !== null && _columnSizingOptions_column_columnId !== void 0 ? _columnSizingOptions_column_columnId : {};
|
|
if (idealWidth !== existingColumnState.idealWidth || minWidth !== existingColumnState.minWidth || padding !== existingColumnState.padding) {
|
|
updated = true;
|
|
return {
|
|
...existingColumnState,
|
|
idealWidth,
|
|
width: idealWidth,
|
|
minWidth,
|
|
padding
|
|
};
|
|
}
|
|
return existingColumnState;
|
|
}
|
|
var _columnSizingOptions_column_columnId1;
|
|
const { defaultWidth, idealWidth = DEFAULT_WIDTH, minWidth = DEFAULT_MIN_WIDTH, padding } = (_columnSizingOptions_column_columnId1 = columnSizingOptions[column.columnId]) !== null && _columnSizingOptions_column_columnId1 !== void 0 ? _columnSizingOptions_column_columnId1 : {};
|
|
updated = true;
|
|
return {
|
|
columnId: column.columnId,
|
|
width: Math.max(defaultWidth !== null && defaultWidth !== void 0 ? defaultWidth : idealWidth, minWidth),
|
|
minWidth,
|
|
idealWidth: Math.max(defaultWidth !== null && defaultWidth !== void 0 ? defaultWidth : idealWidth, minWidth),
|
|
padding: padding !== null && padding !== void 0 ? padding : 16
|
|
};
|
|
});
|
|
// If the length of the new state changed (column was added or removed) or any of
|
|
// the individual states has a new reference (column was replaced),
|
|
// we have to reset the column widths to their ideal width (because the column which was last may not be last now).
|
|
// Then the adjustColumnWidthsToFitContainer can do its job and properly stretch the last column.
|
|
if (updatedState.length !== state.length || updated) {
|
|
const column = updatedState.find((col)=>col.width > col.idealWidth);
|
|
if (column) {
|
|
column.width = column.idealWidth;
|
|
}
|
|
updated = true;
|
|
}
|
|
return updated ? updatedState : state;
|
|
}
|
|
export function getColumnById(state, columnId) {
|
|
return state.find((c)=>c.columnId === columnId);
|
|
}
|
|
export function getColumnByIndex(state, index) {
|
|
return state[index];
|
|
}
|
|
export function getTotalWidth(state) {
|
|
return state.reduce((sum, column)=>sum + column.width + column.padding, 0);
|
|
}
|
|
export function getLength(state) {
|
|
return state.length;
|
|
}
|
|
export function getColumnWidth(state, columnId) {
|
|
const column = getColumnById(state, columnId);
|
|
var _column_width;
|
|
return (_column_width = column === null || column === void 0 ? void 0 : column.width) !== null && _column_width !== void 0 ? _column_width : 0;
|
|
}
|
|
/**
|
|
* This function takes the current state and returns an updated state, so that it can be set.
|
|
* The reason for this is that we can update the state multiple times before commiting to render.
|
|
* This is an optimization and also prevents flickering.
|
|
* It also returns new copy of the state only if the value is different than the one currently in
|
|
* the state, further preventing unnecessary updates.
|
|
* @param localState
|
|
* @param columnId
|
|
* @param property
|
|
* @param value
|
|
* @returns
|
|
*/ export function setColumnProperty(localState, columnId, property, value) {
|
|
const currentColumn = getColumnById(localState, columnId);
|
|
if (!currentColumn || (currentColumn === null || currentColumn === void 0 ? void 0 : currentColumn[property]) === value) {
|
|
return localState;
|
|
}
|
|
const updatedColumn = {
|
|
...currentColumn,
|
|
[property]: value
|
|
};
|
|
const newState = localState.reduce((acc, current)=>{
|
|
if (current.columnId === updatedColumn.columnId) {
|
|
return [
|
|
...acc,
|
|
updatedColumn
|
|
];
|
|
}
|
|
return [
|
|
...acc,
|
|
current
|
|
];
|
|
}, []);
|
|
return newState;
|
|
}
|
|
/**
|
|
* This function takes the state and container width and makes sure the each column in the state
|
|
* is its optimal width, and that the columns
|
|
* a) fit to the container
|
|
* b) always fill the whole container
|
|
* @param state
|
|
* @param containerWidth
|
|
* @returns
|
|
*/ export function adjustColumnWidthsToFitContainer(state, containerWidth) {
|
|
let newState = state;
|
|
const totalWidth = getTotalWidth(newState);
|
|
// The total width is smaller, we are expanding columns
|
|
if (totalWidth < containerWidth) {
|
|
let difference = containerWidth - totalWidth;
|
|
let i = 0;
|
|
// We start at the beginning and assign the columns their ideal width
|
|
while(i < newState.length && difference > 0){
|
|
const currentCol = getColumnByIndex(newState, i);
|
|
if (!currentCol) {
|
|
break;
|
|
}
|
|
const colAdjustment = Math.min(currentCol.idealWidth - currentCol.width, difference);
|
|
newState = setColumnProperty(newState, currentCol.columnId, 'width', currentCol.width + colAdjustment);
|
|
difference -= colAdjustment;
|
|
// if there is still empty space, after all columns are their ideal sizes, assign it to the last column
|
|
if (i === newState.length - 1 && difference !== 0) {
|
|
const lastCol = getColumnByIndex(newState, i);
|
|
if (lastCol) {
|
|
newState = setColumnProperty(newState, lastCol.columnId, 'width', lastCol.width + difference);
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
} else if (totalWidth >= containerWidth) {
|
|
let difference = totalWidth - containerWidth;
|
|
// We start with the last column
|
|
let j = newState.length - 1;
|
|
while(j >= 0 && difference > 0){
|
|
const currentCol = getColumnByIndex(newState, j);
|
|
if (!currentCol) {
|
|
j--;
|
|
continue;
|
|
}
|
|
if (currentCol.width > currentCol.minWidth) {
|
|
const colAdjustment = Math.min(currentCol.width - currentCol.minWidth, difference);
|
|
difference -= colAdjustment;
|
|
newState = setColumnProperty(newState, currentCol.columnId, 'width', currentCol.width - colAdjustment);
|
|
}
|
|
j--;
|
|
}
|
|
}
|
|
return newState;
|
|
}
|